commit
76b647e0a8
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
CONTRIBUTORS.md merge=union
|
|
@ -1,68 +0,0 @@
|
|||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$InstallFFMPEG,
|
||||
[switch]$GenerateZip,
|
||||
[string]$InstallLocation = "$Env:AppData/JellyFin-Server/",
|
||||
[ValidateSet('Debug','Release')][string]$BuildType = 'Release',
|
||||
[ValidateSet('Quiet','Minimal', 'Normal')][string]$DotNetVerbosity = 'Minimal',
|
||||
[ValidateSet('win','win7', 'win8','win81','win10')][string]$WindowsVersion = 'win',
|
||||
[ValidateSet('x64','x86', 'arm', 'arm64')][string]$Architecture = 'x64'
|
||||
)
|
||||
function Build-JellyFin {
|
||||
if($Architecture -eq 'arm64'){
|
||||
if($WindowsVersion -ne 'win10'){
|
||||
Write-Error "arm64 only supported with Windows10 Version"
|
||||
exit
|
||||
}
|
||||
}
|
||||
if($Architecture -eq 'arm'){
|
||||
if($WindowsVersion -notin @('win10','win81','win8')){
|
||||
Write-Error "arm only supported with Windows 8 or higher"
|
||||
exit
|
||||
}
|
||||
}
|
||||
dotnet publish -c $BuildType -r "$windowsversion-$Architecture" MediaBrowser.sln -o $InstallLocation -v $DotNetVerbosity
|
||||
}
|
||||
|
||||
function Install-FFMPEG {
|
||||
param(
|
||||
[string]$InstallLocation,
|
||||
[string]$Architecture
|
||||
)
|
||||
Write-Verbose "Checking Architecture"
|
||||
if($Architecture -notin @('x86','x64')){
|
||||
Write-Warning "No builds available for your selected architecture of $Architecture"
|
||||
Write-Warning "FFMPEG will not be installed"
|
||||
}elseif($Architecture -eq 'x64'){
|
||||
Write-Verbose "Downloading 64 bit FFMPEG"
|
||||
Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-4.1-win64-static.zip -UseBasicParsing -OutFile "$env:TEMP/fmmpeg.zip" | Write-Verbose
|
||||
}else{
|
||||
Write-Verbose "Downloading 32 bit FFMPEG"
|
||||
Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-4.1-win32-static.zip -UseBasicParsing -OutFile "$env:TEMP/fmmpeg.zip" | Write-Verbose
|
||||
}
|
||||
|
||||
Expand-Archive "$env:TEMP/fmmpeg.zip" -DestinationPath "$env:TEMP/ffmpeg/" | Write-Verbose
|
||||
if($Architecture -eq 'x64'){
|
||||
Write-Verbose "Copying Binaries to Jellyfin location"
|
||||
Get-ChildItem "$env:temp/ffmpeg/ffmpeg-4.1-win64-static/bin" | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
|
||||
}
|
||||
}else{
|
||||
Write-Verbose "Copying Binaries to Jellyfin location"
|
||||
Get-ChildItem "$env:temp/ffmpeg/ffmpeg-4.1-win32-static/bin" | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
|
||||
}
|
||||
}
|
||||
Remove-Item "$env:TEMP/ffmpeg/" -Recurse -Force -ErrorAction Continue | Write-Verbose
|
||||
Remove-Item "$env:TEMP/fmmpeg.zip" -Force -ErrorAction Continue | Write-Verbose
|
||||
}
|
||||
Write-Verbose "Starting Build Process: Selected Environment is $WindowsVersion-$Architecture"
|
||||
Build-JellyFin
|
||||
if($InstallFFMPEG.IsPresent -or ($InstallFFMPEG -eq $true)){
|
||||
Write-Verbose "Starting FFMPEG Install"
|
||||
Install-FFMPEG $InstallLocation $Architecture
|
||||
}
|
||||
if($GenerateZip.IsPresent -or ($GenerateZip -eq $true)){
|
||||
Compress-Archive -Path $InstallLocation -DestinationPath "$InstallLocation/jellyfin.zip" -Force
|
||||
}
|
||||
Write-Verbose "Finished"
|
|
@ -1,4 +0,0 @@
|
|||
1. Don't sneakily relicense free software.
|
||||
2. Don't continually nag users to give you money.
|
||||
3. Don't hide binary blobs in otherwise free software.
|
||||
4. Don't needlessly obfuscate the build process or any other part of free software.
|
|
@ -4,6 +4,9 @@
|
|||
- [nvllsvm](https://github.com/nvllsvm)
|
||||
- [JustAMan](https://github.com/JustAMan)
|
||||
- [dcrdev](https://github.com/dcrdev)
|
||||
- [EraYaN](https://github.com/EraYaN)
|
||||
- [flemse](https://github.com/flemse)
|
||||
- [bfayers](https://github.com/bfayers)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
|
|
@ -467,7 +467,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
IsMissing = false,
|
||||
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
|
||||
IsFolder = isFolder,
|
||||
MediaTypes = mediaTypes.ToArray(mediaTypes.Count),
|
||||
MediaTypes = mediaTypes.ToArray(),
|
||||
DtoOptions = GetDtoOptions()
|
||||
});
|
||||
}
|
||||
|
@ -676,7 +676,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
Items = list.ToArray(list.Count),
|
||||
Items = list.ToArray(),
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
}
|
||||
|
@ -754,7 +754,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
Items = list.ToArray(list.Count),
|
||||
Items = list.ToArray(),
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
}
|
||||
|
@ -859,7 +859,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
Items = list.ToArray(list.Count),
|
||||
Items = list.ToArray(),
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
}
|
||||
|
@ -1026,7 +1026,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = genresResult.TotalRecordCount,
|
||||
Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
|
||||
Items = genresResult.Items.Select(i => i.Item1).ToArray()
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -1044,7 +1044,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = genresResult.TotalRecordCount,
|
||||
Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
|
||||
Items = genresResult.Items.Select(i => i.Item1).ToArray()
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -1062,7 +1062,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = artists.TotalRecordCount,
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray()
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -1080,7 +1080,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = artists.TotalRecordCount,
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray()
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -1099,7 +1099,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = artists.TotalRecordCount,
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray()
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -1247,7 +1247,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
var serverItems = result
|
||||
.Select(i => new ServerItem(i))
|
||||
.ToArray(result.Length);
|
||||
.ToArray();
|
||||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
|
|
|
@ -512,7 +512,7 @@ namespace Emby.Dlna.Didl
|
|||
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
|
||||
{
|
||||
ItemId = audio.Id,
|
||||
MediaSources = sources.ToArray(sources.Count),
|
||||
MediaSources = sources.ToArray(),
|
||||
Profile = _profile,
|
||||
DeviceId = deviceId
|
||||
});
|
||||
|
|
|
@ -941,7 +941,7 @@ namespace Emby.Dlna.PlayTo
|
|||
if (room != null && !string.IsNullOrWhiteSpace(room.Value))
|
||||
friendlyNames.Add(room.Value);
|
||||
|
||||
deviceProperties.Name = string.Join(" ", friendlyNames.ToArray(friendlyNames.Count));
|
||||
deviceProperties.Name = string.Join(" ", friendlyNames.ToArray());
|
||||
|
||||
var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
|
||||
if (model != null)
|
||||
|
|
|
@ -571,7 +571,7 @@ namespace Emby.Dlna.PlayTo
|
|||
StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
|
||||
{
|
||||
ItemId = item.Id,
|
||||
MediaSources = mediaSources.ToArray(mediaSources.Count),
|
||||
MediaSources = mediaSources.ToArray(),
|
||||
Profile = profile,
|
||||
DeviceId = deviceId,
|
||||
MaxBitrate = profile.MaxStreamingBitrate,
|
||||
|
|
|
@ -173,7 +173,7 @@ namespace Emby.Dlna.Profiles
|
|||
Value = value
|
||||
});
|
||||
|
||||
XmlRootAttributes = list.ToArray(list.Count);
|
||||
XmlRootAttributes = list.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,7 +242,7 @@ namespace Emby.Dlna.Service
|
|||
}
|
||||
|
||||
var originalHeaders = request.Headers;
|
||||
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(originalHeaders.Count));
|
||||
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
|
||||
|
||||
Logger.Debug("Control request. Headers: {0}", headers);
|
||||
}
|
||||
|
|
|
@ -564,7 +564,7 @@ namespace Emby.Drawing
|
|||
var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
|
||||
cacheKeys.Add(originalImagePath + dateModified.Ticks);
|
||||
|
||||
return string.Join("|", cacheKeys.ToArray(cacheKeys.Count)).GetMD5().ToString("N");
|
||||
return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N");
|
||||
}
|
||||
|
||||
private async Task<ValueTuple<string, DateTime>> GetSupportedImage(string originalImagePath, DateTime dateModified)
|
||||
|
@ -919,4 +919,4 @@ namespace Emby.Drawing
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -466,7 +466,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
{
|
||||
Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
|
||||
Type = NotificationType.TaskFailed.ToString(),
|
||||
Overview = string.Join(Environment.NewLine, vals.ToArray(vals.Count)),
|
||||
Overview = string.Join(Environment.NewLine, vals.ToArray()),
|
||||
ShortOverview = runningTime,
|
||||
Severity = LogSeverity.Error
|
||||
});
|
||||
|
|
|
@ -189,13 +189,13 @@ namespace Emby.Server.Implementations.Activity
|
|||
|
||||
var whereTextWithoutPaging = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
if (startIndex.HasValue && startIndex.Value > 0)
|
||||
{
|
||||
var pagingWhereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLog {0} ORDER BY DateCreated DESC LIMIT {1})",
|
||||
pagingWhereText,
|
||||
|
@ -204,7 +204,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
|
||||
var whereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
commandText += whereText;
|
||||
|
||||
|
@ -249,7 +249,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
|
||||
}
|
||||
|
||||
result.Items = list.ToArray(list.Count);
|
||||
result.Items = list.ToArray();
|
||||
return result;
|
||||
|
||||
}, ReadTransactionMode);
|
||||
|
|
|
@ -728,7 +728,7 @@ namespace Emby.Server.Implementations
|
|||
|
||||
Logger.Info("ServerId: {0}", SystemId);
|
||||
|
||||
var entryPoints = GetExports<IServerEntryPoint>().ToList();
|
||||
var entryPoints = GetExports<IServerEntryPoint>();
|
||||
RunEntryPoints(entryPoints, true);
|
||||
|
||||
Logger.Info("Core startup complete");
|
||||
|
@ -1962,6 +1962,7 @@ namespace Emby.Server.Implementations
|
|||
public async Task<SystemInfo> GetSystemInfo(CancellationToken cancellationToken)
|
||||
{
|
||||
var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
|
||||
var wanAddress = await GetWanApiUrl(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return new SystemInfo
|
||||
{
|
||||
|
@ -1984,8 +1985,7 @@ namespace Emby.Server.Implementations
|
|||
CanSelfRestart = CanSelfRestart,
|
||||
CanSelfUpdate = CanSelfUpdate,
|
||||
CanLaunchWebBrowser = CanLaunchWebBrowser,
|
||||
// TODO - remove WanAddress
|
||||
WanAddress = "0.0.0.0",
|
||||
WanAddress = wanAddress,
|
||||
HasUpdateAvailable = HasUpdateAvailable,
|
||||
SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
|
||||
TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
|
||||
|
@ -2012,14 +2012,13 @@ namespace Emby.Server.Implementations
|
|||
public async Task<PublicSystemInfo> GetPublicSystemInfo(CancellationToken cancellationToken)
|
||||
{
|
||||
var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var wanAddress = await GetWanApiUrl(cancellationToken).ConfigureAwait(false);
|
||||
return new PublicSystemInfo
|
||||
{
|
||||
Version = ApplicationVersion.ToString(),
|
||||
Id = SystemId,
|
||||
OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
|
||||
// TODO - remove WanAddress
|
||||
WanAddress = "0.0.0.0",
|
||||
WanAddress = wanAddress,
|
||||
ServerName = FriendlyName,
|
||||
LocalAddress = localAddress
|
||||
};
|
||||
|
@ -2060,6 +2059,32 @@ namespace Emby.Server.Implementations
|
|||
return null;
|
||||
}
|
||||
|
||||
public async Task<string> GetWanApiUrl(CancellationToken cancellationToken)
|
||||
{
|
||||
var url = "http://ipv4.icanhazip.com";
|
||||
try
|
||||
{
|
||||
using (var response = await HttpClient.Get(new HttpRequestOptions
|
||||
{
|
||||
Url = url,
|
||||
LogErrorResponseBody = false,
|
||||
LogErrors = false,
|
||||
LogRequest = false,
|
||||
TimeoutMs = 10000,
|
||||
BufferContent = false,
|
||||
CancellationToken = cancellationToken
|
||||
}))
|
||||
{
|
||||
return GetLocalApiUrl(response.ReadToEnd().Trim());
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error getting WAN Ip address information", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetLocalApiUrl(IpAddressInfo ipAddress)
|
||||
{
|
||||
if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
|
||||
|
|
|
@ -239,7 +239,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
all = all.Take(query.Limit.Value).ToList();
|
||||
}
|
||||
|
||||
var returnItems = all.ToArray(all.Count);
|
||||
var returnItems = all.ToArray();
|
||||
|
||||
if (query.RefreshLatestChannelItems)
|
||||
{
|
||||
|
@ -1011,7 +1011,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
{
|
||||
item.Name = info.Name;
|
||||
item.Genres = info.Genres.ToArray();
|
||||
item.Studios = info.Studios.ToArray(info.Studios.Count);
|
||||
item.Studios = info.Studios.ToArray();
|
||||
item.CommunityRating = info.CommunityRating;
|
||||
item.Overview = info.Overview;
|
||||
item.IndexNumber = info.IndexNumber;
|
||||
|
@ -1021,7 +1021,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
item.ProviderIds = info.ProviderIds;
|
||||
item.OfficialRating = info.OfficialRating;
|
||||
item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
|
||||
item.Tags = info.Tags.ToArray(info.Tags.Count);
|
||||
item.Tags = info.Tags.ToArray();
|
||||
item.OriginalTitle = info.OriginalTitle;
|
||||
}
|
||||
else if (info.Type == ChannelItemType.Folder && info.FolderType == ChannelFolderType.Container)
|
||||
|
@ -1043,7 +1043,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
var hasAlbumArtists = item as IHasAlbumArtist;
|
||||
if (hasAlbumArtists != null)
|
||||
{
|
||||
hasAlbumArtists.AlbumArtists = info.AlbumArtists.ToArray(info.AlbumArtists.Count);
|
||||
hasAlbumArtists.AlbumArtists = info.AlbumArtists.ToArray();
|
||||
}
|
||||
|
||||
var trailer = item as Trailer;
|
||||
|
|
|
@ -219,7 +219,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
{
|
||||
var newList = collection.LinkedChildren.ToList();
|
||||
newList.AddRange(list);
|
||||
collection.LinkedChildren = newList.ToArray(newList.Count);
|
||||
collection.LinkedChildren = newList.ToArray();
|
||||
|
||||
collection.UpdateRatingToItems(linkedChildrenList);
|
||||
|
||||
|
|
|
@ -1148,7 +1148,7 @@ namespace Emby.Server.Implementations.Data
|
|||
}
|
||||
}
|
||||
|
||||
item.ImageInfos = list.ToArray(list.Count);
|
||||
item.ImageInfos = list.ToArray();
|
||||
}
|
||||
|
||||
public string ToValueString(ItemImageInfo image)
|
||||
|
@ -2566,7 +2566,7 @@ namespace Emby.Server.Implementations.Data
|
|||
excludeIds.Add(item.Id);
|
||||
excludeIds.AddRange(item.ExtraIds);
|
||||
|
||||
query.ExcludeItemIds = excludeIds.ToArray(excludeIds.Count);
|
||||
query.ExcludeItemIds = excludeIds.ToArray();
|
||||
query.ExcludeProviderIds = item.ProviderIds;
|
||||
}
|
||||
|
||||
|
@ -2587,7 +2587,7 @@ namespace Emby.Server.Implementations.Data
|
|||
list.Add(builder.ToString());
|
||||
}
|
||||
|
||||
return list.ToArray(list.Count);
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
private void BindSearchParams(InternalItemsQuery query, IStatement statement)
|
||||
|
@ -2666,7 +2666,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
if (groups.Count > 0)
|
||||
{
|
||||
return " Group by " + string.Join(",", groups.ToArray(groups.Count));
|
||||
return " Group by " + string.Join(",", groups.ToArray());
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
|
@ -2703,7 +2703,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
var whereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
commandText += whereText;
|
||||
|
||||
|
@ -2761,7 +2761,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
var whereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
commandText += whereText;
|
||||
|
||||
|
@ -2938,7 +2938,7 @@ namespace Emby.Server.Implementations.Data
|
|||
var returnList = GetItemList(query);
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
Items = returnList.ToArray(returnList.Count),
|
||||
Items = returnList.ToArray(),
|
||||
TotalRecordCount = returnList.Count
|
||||
};
|
||||
}
|
||||
|
@ -2961,7 +2961,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
var whereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
var whereTextWithoutPaging = whereText;
|
||||
|
||||
|
@ -3079,7 +3079,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
LogQueryTime("GetItems", commandText, now);
|
||||
|
||||
result.Items = list.ToArray(list.Count);
|
||||
result.Items = list.ToArray();
|
||||
return result;
|
||||
|
||||
}, ReadTransactionMode);
|
||||
|
@ -3227,7 +3227,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
var whereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
commandText += whereText;
|
||||
|
||||
|
@ -3299,7 +3299,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
var whereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
commandText += whereText;
|
||||
|
||||
|
@ -3372,7 +3372,7 @@ namespace Emby.Server.Implementations.Data
|
|||
var returnList = GetItemIdsList(query);
|
||||
return new QueryResult<Guid>
|
||||
{
|
||||
Items = returnList.ToArray(returnList.Count),
|
||||
Items = returnList.ToArray(),
|
||||
TotalRecordCount = returnList.Count
|
||||
};
|
||||
}
|
||||
|
@ -3387,7 +3387,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
var whereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
var whereTextWithoutPaging = whereText;
|
||||
|
||||
|
@ -3495,7 +3495,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
LogQueryTime("GetItemIds", commandText, now);
|
||||
|
||||
result.Items = list.ToArray(list.Count);
|
||||
result.Items = list.ToArray();
|
||||
return result;
|
||||
|
||||
}, ReadTransactionMode);
|
||||
|
@ -3690,7 +3690,7 @@ namespace Emby.Server.Implementations.Data
|
|||
statement.TryBind("@IsMovie", true);
|
||||
}
|
||||
|
||||
whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray(programAttribtues.Count)) + ")");
|
||||
whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray()) + ")");
|
||||
}
|
||||
else if (query.IsMovie.HasValue)
|
||||
{
|
||||
|
@ -5813,7 +5813,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||
{
|
||||
result.TotalRecordCount = list.Count;
|
||||
}
|
||||
result.Items = list.ToArray(list.Count);
|
||||
result.Items = list.ToArray();
|
||||
|
||||
return result;
|
||||
|
||||
|
|
|
@ -289,7 +289,7 @@ namespace Emby.Server.Implementations.Devices
|
|||
|
||||
var list = history.FilesUploaded.ToList();
|
||||
list.Add(file);
|
||||
history.FilesUploaded = list.ToArray(list.Count);
|
||||
history.FilesUploaded = list.ToArray();
|
||||
|
||||
_json.SerializeToFile(history, path);
|
||||
}
|
||||
|
@ -501,4 +501,4 @@ namespace Emby.Server.Implementations.Devices
|
|||
return config.GetConfiguration<DevicesOptions>("devices");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -648,7 +648,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
}
|
||||
}
|
||||
|
||||
dto.People = list.ToArray(list.Count);
|
||||
dto.People = list.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -12,7 +12,6 @@ using MediaBrowser.Model.Events;
|
|||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using Mono.Nat;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using System.Threading;
|
||||
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
|
@ -59,7 +58,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
values.Add(_appHost.EnableHttps.ToString());
|
||||
values.Add((config.EnableRemoteAccess).ToString());
|
||||
|
||||
return string.Join("|", values.ToArray(values.Count));
|
||||
return string.Join("|", values.ToArray());
|
||||
}
|
||||
|
||||
void _config_ConfigurationUpdated(object sender, EventArgs e)
|
||||
|
@ -316,4 +315,4 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
session.ApplicationVersion
|
||||
};
|
||||
|
||||
var key = string.Join("_", keys.ToArray(keys.Count)).GetMD5();
|
||||
var key = string.Join("_", keys.ToArray()).GetMD5();
|
||||
|
||||
ClientInfo info;
|
||||
if (!_apps.TryGetValue(key, out info))
|
||||
|
|
|
@ -825,7 +825,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
});
|
||||
}
|
||||
|
||||
return routes.ToArray(routes.Count);
|
||||
return routes.ToArray();
|
||||
}
|
||||
|
||||
public Func<string, object> GetParseFn(Type propertyType)
|
||||
|
@ -954,4 +954,4 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
_listener.Start(UrlPrefixes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,12 +112,15 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
/// </summary>
|
||||
private IHasHeaders GetHttpResult(IRequest requestContext, byte[] content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null)
|
||||
{
|
||||
string compressionType = null;
|
||||
bool isHeadRequest = false;
|
||||
|
||||
if (requestContext != null) {
|
||||
compressionType = GetCompressionType(requestContext, content, contentType);
|
||||
isHeadRequest = string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
IHasHeaders result;
|
||||
|
||||
var compressionType = requestContext == null ? null : GetCompressionType(requestContext, content, contentType);
|
||||
|
||||
var isHeadRequest = string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (string.IsNullOrEmpty(compressionType))
|
||||
{
|
||||
var contentLength = content.Length;
|
||||
|
@ -791,4 +794,4 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
{
|
||||
byte[] Compress(byte[] content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
// TODO: @bond Remove
|
||||
namespace SharpCifs.Util.Sharpen
|
||||
{
|
||||
internal static class Collections<T>
|
||||
|
|
|
@ -730,7 +730,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
_fileSystem.CreateDirectory(rootFolderPath);
|
||||
|
||||
var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath));
|
||||
var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))).DeepCopy<Folder,AggregateFolder>();
|
||||
|
||||
// In case program data folder was moved
|
||||
if (!string.Equals(rootFolder.Path, rootFolderPath, StringComparison.Ordinal))
|
||||
|
@ -799,7 +799,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (tmpItem == null)
|
||||
{
|
||||
tmpItem = (UserRootFolder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath));
|
||||
tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath))).DeepCopy<Folder,UserRootFolder>();
|
||||
}
|
||||
|
||||
// In case program data folder was moved
|
||||
|
@ -1493,7 +1493,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
Items = list.ToArray(list.Count)
|
||||
Items = list.ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -161,8 +161,8 @@ namespace Emby.Server.Implementations.Library
|
|||
var searchQuery = new InternalItemsQuery(user)
|
||||
{
|
||||
SearchTerm = searchTerm,
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
|
||||
IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(),
|
||||
IncludeItemTypes = includeItemTypes.ToArray(),
|
||||
Limit = query.Limit,
|
||||
IncludeItemsByName = string.IsNullOrEmpty(query.ParentId),
|
||||
ParentId = string.IsNullOrEmpty(query.ParentId) ? Guid.Empty : new Guid(query.ParentId),
|
||||
|
|
|
@ -354,7 +354,7 @@ namespace Emby.Server.Implementations.Library
|
|||
Limit = limit * 5,
|
||||
IsPlayed = isPlayed,
|
||||
DtoOptions = options,
|
||||
MediaTypes = mediaTypes.ToArray(mediaTypes.Count)
|
||||
MediaTypes = mediaTypes.ToArray()
|
||||
};
|
||||
|
||||
if (parents.Count == 0)
|
||||
|
|
|
@ -139,7 +139,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
dto.ProgramId = GetInternalProgramId(info.ProgramId).ToString("N");
|
||||
}
|
||||
|
||||
dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days.ToArray(info.Days.Count));
|
||||
dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days.ToArray());
|
||||
|
||||
FillImages(dto, info.Name, info.SeriesId);
|
||||
|
||||
|
|
|
@ -1140,7 +1140,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
var dtoOptions = new DtoOptions();
|
||||
var fields = dtoOptions.Fields.ToList();
|
||||
fields.Remove(ItemFields.BasicSyncInfo);
|
||||
dtoOptions.Fields = fields.ToArray(fields.Count);
|
||||
dtoOptions.Fields = fields.ToArray();
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
@ -1458,16 +1458,16 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
MediaTypes = new[] { MediaType.Video },
|
||||
Recursive = true,
|
||||
AncestorIds = folderIds.ToArray(folderIds.Count),
|
||||
AncestorIds = folderIds.ToArray(),
|
||||
IsFolder = false,
|
||||
IsVirtualItem = false,
|
||||
Limit = limit,
|
||||
StartIndex = query.StartIndex,
|
||||
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
|
||||
EnableTotalRecordCount = query.EnableTotalRecordCount,
|
||||
IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
|
||||
Genres = genres.ToArray(genres.Count),
|
||||
IncludeItemTypes = includeItemTypes.ToArray(),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(),
|
||||
Genres = genres.ToArray(),
|
||||
DtoOptions = dtoOptions
|
||||
});
|
||||
|
||||
|
@ -1791,7 +1791,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
var returnArray = returnList
|
||||
.OrderBy(i => i.StartDate)
|
||||
.ToArray(returnList.Count);
|
||||
.ToArray();
|
||||
|
||||
return new QueryResult<TimerInfoDto>
|
||||
{
|
||||
|
@ -2338,7 +2338,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
fields.Remove(ItemFields.CanDownload);
|
||||
fields.Remove(ItemFields.DisplayPreferencesId);
|
||||
fields.Remove(ItemFields.Etag);
|
||||
options.Fields = fields.ToArray(fields.Count);
|
||||
options.Fields = fields.ToArray();
|
||||
}
|
||||
|
||||
public Folder GetInternalLiveTvFolder(CancellationToken cancellationToken)
|
||||
|
@ -2373,7 +2373,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
info.Id = Guid.NewGuid().ToString("N");
|
||||
list.Add(info);
|
||||
config.TunerHosts = list.ToArray(list.Count);
|
||||
config.TunerHosts = list.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2412,7 +2412,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
info.Id = Guid.NewGuid().ToString("N");
|
||||
list.Add(info);
|
||||
config.ListingProviders = list.ToArray(list.Count);
|
||||
config.ListingProviders = list.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2451,7 +2451,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
Name = tunerChannelId,
|
||||
Value = providerChannelId
|
||||
});
|
||||
listingsProviderInfo.ChannelMappings = list.ToArray(list.Count);
|
||||
listingsProviderInfo.ChannelMappings = list.ToArray();
|
||||
}
|
||||
|
||||
_config.SaveConfiguration("livetv", config);
|
||||
|
@ -2602,4 +2602,4 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
return folders.Cast<BaseItem>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
openKeys.Add(item.GetType().Name);
|
||||
openKeys.Add(item.Id.ToString("N"));
|
||||
openKeys.Add(source.Id ?? string.Empty);
|
||||
source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray(openKeys.Count));
|
||||
source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray());
|
||||
}
|
||||
|
||||
// Dummy this up so that direct play checks can still run
|
||||
|
|
|
@ -706,7 +706,7 @@ namespace Emby.Server.Implementations.Networking
|
|||
public async Task<IpAddressInfo[]> GetHostAddressesAsync(string host)
|
||||
{
|
||||
var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
|
||||
return addresses.Select(ToIpAddressInfo).ToArray(addresses.Length);
|
||||
return addresses.Select(ToIpAddressInfo).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -208,7 +208,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||
|
||||
var newList = playlist.LinkedChildren.ToList();
|
||||
newList.AddRange(list);
|
||||
playlist.LinkedChildren = newList.ToArray(newList.Count);
|
||||
playlist.LinkedChildren = newList.ToArray();
|
||||
|
||||
playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
|
||||
|
||||
|
@ -290,7 +290,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||
newList.Insert(newIndex, item);
|
||||
}
|
||||
|
||||
playlist.LinkedChildren = newList.ToArray(newList.Count);
|
||||
playlist.LinkedChildren = newList.ToArray();
|
||||
|
||||
playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
|
||||
_fileSystem.CreateDirectory(parentPath);
|
||||
|
||||
_fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray(previouslyFailedImages.Count)));
|
||||
_fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace Emby.Server.Implementations.ScheduledTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Plugin Update Task
|
||||
/// </summary>
|
||||
public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly IInstallationManager _installationManager;
|
||||
|
||||
private readonly IApplicationHost _appHost;
|
||||
|
||||
public PluginUpdateTask(ILogger logger, IInstallationManager installationManager, IApplicationHost appHost)
|
||||
{
|
||||
_logger = logger;
|
||||
_installationManager = installationManager;
|
||||
_appHost = appHost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the triggers that define when the task will run
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
|
||||
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||
{
|
||||
return new[] {
|
||||
|
||||
// At startup
|
||||
new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup},
|
||||
|
||||
// Every so often
|
||||
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
|
||||
};
|
||||
}
|
||||
|
||||
public string Key
|
||||
{
|
||||
get { return "PluginUpdates"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update installed plugins
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
progress.Report(0);
|
||||
|
||||
var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, true, cancellationToken).ConfigureAwait(false)).ToList();
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var package in packagesToInstall)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// InstallPackage has it's own inner cancellation token, so only throw this if it's ours
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_logger.ErrorException("Error downloading {0}", ex, package.name);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating {0}", ex, package.name);
|
||||
}
|
||||
|
||||
// Update progress
|
||||
lock (progress)
|
||||
{
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= packagesToInstall.Count;
|
||||
|
||||
progress.Report(90 * percent + 10);
|
||||
}
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the task
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return "Check for plugin updates"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description.
|
||||
/// </summary>
|
||||
/// <value>The description.</value>
|
||||
public string Description
|
||||
{
|
||||
get { return "Downloads and installs updates for plugins that are configured to update automatically."; }
|
||||
}
|
||||
|
||||
public string Category
|
||||
{
|
||||
get { return "Application"; }
|
||||
}
|
||||
|
||||
public bool IsHidden => true;
|
||||
|
||||
public bool IsEnabled => true;
|
||||
|
||||
public bool IsLogged => true;
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ using MediaBrowser.Common.Events;
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
@ -276,7 +275,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
get
|
||||
{
|
||||
var triggers = InternalTriggers;
|
||||
return triggers.Select(i => i.Item1).ToArray(triggers.Length);
|
||||
return triggers.Select(i => i.Item1).ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
|
@ -290,7 +289,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
|
||||
SaveTriggers(triggerList);
|
||||
|
||||
InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray(triggerList.Length);
|
||||
InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ namespace Emby.Server.Implementations.Security
|
|||
|
||||
var whereTextWithoutPaging = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
|
||||
commandText += whereTextWithoutPaging;
|
||||
|
||||
|
@ -298,7 +298,7 @@ namespace Emby.Server.Implementations.Security
|
|||
}
|
||||
}
|
||||
|
||||
result.Items = list.ToArray(list.Count);
|
||||
result.Items = list.ToArray();
|
||||
return result;
|
||||
|
||||
}, ReadTransactionMode);
|
||||
|
|
|
@ -181,7 +181,7 @@ namespace Emby.Server.Implementations.Services
|
|||
}
|
||||
|
||||
if (reqFilters.Count > 0)
|
||||
actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray(reqFilters.Count);
|
||||
actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray();
|
||||
|
||||
actions.Add(actionCtx);
|
||||
}
|
||||
|
@ -220,4 +220,4 @@ namespace Emby.Server.Implementations.Services
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,13 +132,13 @@ namespace Emby.Server.Implementations.Services
|
|||
}
|
||||
}
|
||||
|
||||
var components = componentsList.ToArray(componentsList.Count);
|
||||
var components = componentsList.ToArray();
|
||||
this.TotalComponentsCount = components.Length;
|
||||
|
||||
this.literalsToMatch = new string[this.TotalComponentsCount];
|
||||
this.variablesNames = new string[this.TotalComponentsCount];
|
||||
this.isWildcard = new bool[this.TotalComponentsCount];
|
||||
this.componentsWithSeparators = hasSeparators.ToArray(hasSeparators.Count);
|
||||
this.componentsWithSeparators = hasSeparators.ToArray();
|
||||
this.PathComponentsCount = this.componentsWithSeparators.Length;
|
||||
string firstLiteralMatch = null;
|
||||
|
||||
|
@ -297,7 +297,7 @@ namespace Emby.Server.Implementations.Services
|
|||
if (mi != null && mi.IsStatic) continue;
|
||||
pis.Add(pi);
|
||||
}
|
||||
return pis.ToArray(pis.Count);
|
||||
return pis.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -463,7 +463,7 @@ namespace Emby.Server.Implementations.Services
|
|||
}
|
||||
}
|
||||
|
||||
withPathInfoParts = totalComponents.ToArray(totalComponents.Count);
|
||||
withPathInfoParts = totalComponents.ToArray();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -574,4 +574,4 @@ namespace Emby.Server.Implementations.Services
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1042,7 +1042,7 @@ namespace Emby.Server.Implementations.Session
|
|||
command.PlayCommand = PlayCommand.PlayNow;
|
||||
}
|
||||
|
||||
command.ItemIds = items.Select(i => i.Id).ToArray(items.Count);
|
||||
command.ItemIds = items.Select(i => i.Id).ToArray();
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
|
@ -1070,7 +1070,7 @@ namespace Emby.Server.Implementations.Session
|
|||
|
||||
if (episodes.Count > 0)
|
||||
{
|
||||
command.ItemIds = episodes.Select(i => i.Id).ToArray(episodes.Count);
|
||||
command.ItemIds = episodes.Select(i => i.Id).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1316,7 +1316,7 @@ namespace Emby.Server.Implementations.Session
|
|||
UserName = user.Name
|
||||
});
|
||||
|
||||
session.AdditionalUsers = list.ToArray(list.Count);
|
||||
session.AdditionalUsers = list.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1345,7 +1345,7 @@ namespace Emby.Server.Implementations.Session
|
|||
var list = session.AdditionalUsers.ToList();
|
||||
list.Remove(user);
|
||||
|
||||
session.AdditionalUsers = list.ToArray(list.Count);
|
||||
session.AdditionalUsers = list.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1669,7 +1669,7 @@ namespace Emby.Server.Implementations.Session
|
|||
fields.Remove(ItemFields.Tags);
|
||||
fields.Remove(ItemFields.ExtraIds);
|
||||
|
||||
dtoOptions.Fields = fields.ToArray(fields.Count);
|
||||
dtoOptions.Fields = fields.ToArray();
|
||||
|
||||
_itemInfoDtoOptions = dtoOptions;
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
var list = options.Fields.ToList();
|
||||
list.Add(Model.Querying.ItemFields.RecursiveItemCount);
|
||||
options.Fields = list.ToArray(list.Count);
|
||||
options.Fields = list.ToArray();
|
||||
}
|
||||
|
||||
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
|
@ -156,7 +156,7 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
var list = options.Fields.ToList();
|
||||
list.Add(Model.Querying.ItemFields.ChildCount);
|
||||
options.Fields = list.ToArray(list.Count);
|
||||
options.Fields = list.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -974,7 +974,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
fields.Remove(ItemFields.CanDownload);
|
||||
fields.Remove(ItemFields.DisplayPreferencesId);
|
||||
fields.Remove(ItemFields.Etag);
|
||||
options.Fields = fields.ToArray(fields.Count);
|
||||
options.Fields = fields.ToArray();
|
||||
}
|
||||
|
||||
public object Get(GetChannel request)
|
||||
|
@ -1265,4 +1265,4 @@ namespace MediaBrowser.Api.LiveTv
|
|||
return _liveTvManager.ResetTuner(request.Id, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ namespace MediaBrowser.Api.Movies
|
|||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Limit = request.Limit,
|
||||
IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
SimilarTo = item,
|
||||
EnableGroupByMetadataKey = true,
|
||||
|
@ -177,12 +177,12 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
OrderBy = new[] { ItemSortBy.Random }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
|
||||
Limit = 10,
|
||||
IsFavoriteOrLiked = true,
|
||||
ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id).ToArray(recentlyPlayedMovies.Count),
|
||||
ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id).ToArray(),
|
||||
EnableGroupByMetadataKey = true,
|
||||
ParentId = parentIdGuid,
|
||||
Recursive = true,
|
||||
|
@ -265,7 +265,7 @@ namespace MediaBrowser.Api.Movies
|
|||
// Account for duplicates by imdb id, since the database doesn't support this yet
|
||||
Limit = itemLimit + 2,
|
||||
PersonTypes = new[] { PersonType.Director },
|
||||
IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
EnableGroupByMetadataKey = true,
|
||||
DtoOptions = dtoOptions
|
||||
|
@ -305,7 +305,7 @@ namespace MediaBrowser.Api.Movies
|
|||
Person = name,
|
||||
// Account for duplicates by imdb id, since the database doesn't support this yet
|
||||
Limit = itemLimit + 2,
|
||||
IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
EnableGroupByMetadataKey = true,
|
||||
DtoOptions = dtoOptions
|
||||
|
@ -343,7 +343,7 @@ namespace MediaBrowser.Api.Movies
|
|||
var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Limit = itemLimit,
|
||||
IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
SimilarTo = item,
|
||||
EnableGroupByMetadataKey = true,
|
||||
|
|
|
@ -11,7 +11,6 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Services;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Api
|
||||
{
|
||||
|
@ -81,7 +80,7 @@ namespace MediaBrowser.Api
|
|||
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(includeTypes.Length),
|
||||
IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(),
|
||||
Recursive = true,
|
||||
DtoOptions = dtoOptions
|
||||
};
|
||||
|
|
|
@ -206,7 +206,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = dtos.ToArray(result.Items.Length),
|
||||
Items = dtos.ToArray(),
|
||||
TotalRecordCount = result.TotalRecordCount
|
||||
};
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
fields.Add(ItemFields.PrimaryImageAspectRatio);
|
||||
fields.Add(ItemFields.DisplayPreferencesId);
|
||||
fields.Remove(ItemFields.BasicSyncInfo);
|
||||
dtoOptions.Fields = fields.ToArray(fields.Count);
|
||||
dtoOptions.Fields = fields.ToArray();
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
|
|
|
@ -1295,7 +1295,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
return string.Join("/", terms.ToArray(terms.Count));
|
||||
return string.Join("/", terms.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1536,7 +1536,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
|
||||
|
||||
var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToArray(newThemeVideos.Length);
|
||||
var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToArray();
|
||||
|
||||
var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
|
||||
|
||||
|
@ -1573,7 +1573,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
private async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
|
||||
var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToArray(newThemeSongs.Length);
|
||||
var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToArray();
|
||||
|
||||
var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
|
||||
|
||||
|
@ -2110,9 +2110,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
else
|
||||
{
|
||||
var list = current.ToArray(current.Length + 1);
|
||||
list[list.Length - 1] = name;
|
||||
Studios = list;
|
||||
var list =
|
||||
Studios = current.Concat(new [] { name }).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2252,9 +2251,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
else
|
||||
{
|
||||
var currentCount = ImageInfos.Length;
|
||||
var newList = ImageInfos.ToArray(currentCount + 1);
|
||||
newList[currentCount] = image;
|
||||
ImageInfos = newList;
|
||||
ImageInfos = ImageInfos.Concat(new [] { image }) .ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2269,10 +2266,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
if (image == null)
|
||||
{
|
||||
var currentCount = ImageInfos.Length;
|
||||
var newList = ImageInfos.ToArray(currentCount + 1);
|
||||
newList[currentCount] = GetImageInfo(file, type);
|
||||
ImageInfos = newList;
|
||||
ImageInfos = ImageInfos.Concat(new [] { GetImageInfo(file, type) }) .ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2486,16 +2480,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
if (newImageList.Count > 0)
|
||||
{
|
||||
var currentCount = ImageInfos.Length;
|
||||
var newList = ImageInfos.ToArray(currentCount + newImageList.Count);
|
||||
|
||||
foreach (var image in newImageList)
|
||||
{
|
||||
newList[currentCount] = GetImageInfo(image, imageType);
|
||||
currentCount++;
|
||||
}
|
||||
|
||||
ImageInfos = newList;
|
||||
ImageInfos = ImageInfos.Concat(newImageList.Select(i => GetImageInfo(i, imageType))).ToArray();
|
||||
}
|
||||
|
||||
return imageUpdated || newImageList.Count > 0;
|
||||
|
@ -2537,7 +2522,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
var extensions = new List<string> { ".nfo", ".xml", ".srt", ".vtt", ".sub", ".idx", ".txt", ".edl", ".bif", ".smi", ".ttml" };
|
||||
extensions.AddRange(SupportedImageExtensions);
|
||||
|
||||
return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(extensions.Count), false, false)
|
||||
return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(), false, false)
|
||||
.Where(i => System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
}
|
||||
|
@ -2776,7 +2761,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var list = GetEtagValues(user);
|
||||
|
||||
return string.Join("|", list.ToArray(list.Count)).GetMD5().ToString("N");
|
||||
return string.Join("|", list.ToArray()).GetMD5().ToString("N");
|
||||
}
|
||||
|
||||
protected virtual List<string> GetEtagValues(User user)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -61,5 +62,46 @@ namespace MediaBrowser.Controller.Entities
|
|||
item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies all properties on object. Skips properties that do not exist.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="dest">The destination object.</param>
|
||||
public static void DeepCopy<T, TU>(this T source, TU dest)
|
||||
where T : BaseItem
|
||||
where TU : BaseItem
|
||||
{
|
||||
var sourceProps = typeof (T).GetProperties().Where(x => x.CanRead).ToList();
|
||||
var destProps = typeof(TU).GetProperties()
|
||||
.Where(x => x.CanWrite)
|
||||
.ToList();
|
||||
|
||||
foreach (var sourceProp in sourceProps)
|
||||
{
|
||||
if (destProps.Any(x => x.Name == sourceProp.Name))
|
||||
{
|
||||
var p = destProps.First(x => x.Name == sourceProp.Name);
|
||||
p.SetValue(dest, sourceProp.GetValue(source, null), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies all properties on newly created object. Skips properties that do not exist.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object.</param>
|
||||
public static TU DeepCopy<T, TU>(this T source)
|
||||
where T : BaseItem
|
||||
where TU : BaseItem, new()
|
||||
{
|
||||
var dest = new TU();
|
||||
source.DeepCopy(dest);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,7 +275,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer(FileSystem));
|
||||
|
||||
LinkedChildren = linkedChildren.ToArray(linkedChildren.Count);
|
||||
LinkedChildren = linkedChildren.ToArray();
|
||||
|
||||
var folderIds = PhysicalFolderIds;
|
||||
var newFolderIds = physicalFolders.Select(i => i.Id).ToArray();
|
||||
|
|
|
@ -35,10 +35,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
else
|
||||
{
|
||||
var list = item.RemoteTrailers.ToArray(item.RemoteTrailers.Length + 1);
|
||||
list[list.Length - 1] = mediaUrl;
|
||||
|
||||
item.RemoteTrailers = list;
|
||||
item.RemoteTrailers = item.RemoteTrailers.Concat(new [] { mediaUrl }).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -914,7 +914,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
// Try to preserve order
|
||||
return result.OrderBy(i => ids.IndexOf(i.Id)).ToArray();
|
||||
}
|
||||
return result.ToArray(result.Count);
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
return GetItemsInternal(query).Items;
|
||||
|
@ -1608,7 +1608,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
Logger.Info("Shortcut links have changed for {0}", Path);
|
||||
|
||||
newShortcutLinks.AddRange(LinkedChildren.Where(i => i.Type == LinkedChildType.Manual));
|
||||
LinkedChildren = newShortcutLinks.ToArray(newShortcutLinks.Count);
|
||||
LinkedChildren = newShortcutLinks.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -24,10 +22,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
else
|
||||
{
|
||||
var list = current.ToArray(current.Length + 1);
|
||||
list[list.Length - 1] = name;
|
||||
|
||||
item.Tags = list;
|
||||
item.Tags = current.Concat(new [] { name }).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||
using System.Xml;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Xml;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.LocalMetadata.Parsers
|
||||
{
|
||||
|
@ -85,7 +84,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
}
|
||||
}
|
||||
|
||||
item.Item.LinkedChildren = list.ToArray(list.Count);
|
||||
item.Item.LinkedChildren = list.ToArray();
|
||||
}
|
||||
|
||||
public BoxSetXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
}
|
||||
}
|
||||
|
||||
item.LinkedChildren = list.ToArray(list.Count);
|
||||
item.LinkedChildren = list.ToArray();
|
||||
}
|
||||
|
||||
public PlaylistXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)
|
||||
|
|
|
@ -1,33 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs">
|
||||
<Link>Properties\SharedVersion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\SharedVersion.cs"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BDInfo\BDInfo.csproj">
|
||||
<Project>{88ae38df-19d7-406f-a6a9-09527719a21e}</Project>
|
||||
<Name>BDInfo</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
|
||||
<Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
|
||||
<Name>OpenSubtitlesHandler</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\BDInfo\BDInfo.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
<ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -246,7 +246,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
SortRemoveCharacters = new[] { ",", "&", "-", "{", "}", "'" };
|
||||
SortRemoveWords = new[] { "the", "a", "an" };
|
||||
|
||||
UICulture = "en-us";
|
||||
UICulture = "en-US";
|
||||
|
||||
MetadataOptions = new[]
|
||||
{
|
||||
|
@ -310,4 +310,4 @@ namespace MediaBrowser.Model.Configuration
|
|||
public string From { get; set; }
|
||||
public string To { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
{
|
||||
list.Add(MediaFormatProfile.MPEG_TS_JP_T);
|
||||
}
|
||||
return list.ToArray(list.Count);
|
||||
return list.ToArray();
|
||||
}
|
||||
if (StringHelper.EqualsIgnoreCase(videoCodec, "h264"))
|
||||
{
|
||||
|
|
|
@ -186,7 +186,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
list.Add(string.Format("{0}={1}", pair.Name, encodedValue));
|
||||
}
|
||||
|
||||
string queryString = string.Join("&", list.ToArray(list.Count));
|
||||
string queryString = string.Join("&", list.ToArray());
|
||||
|
||||
return GetUrl(baseUrl, queryString);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
@ -104,7 +105,7 @@ namespace MediaBrowser.Model.Entities
|
|||
attributes.Add("Default");
|
||||
}
|
||||
|
||||
return string.Join(" ", attributes.ToArray(attributes.Count));
|
||||
return string.Join(" ", attributes.ToArray());
|
||||
}
|
||||
|
||||
if (Type == MediaStreamType.Video)
|
||||
|
@ -123,7 +124,7 @@ namespace MediaBrowser.Model.Entities
|
|||
attributes.Add(Codec.ToUpper());
|
||||
}
|
||||
|
||||
return string.Join(" ", attributes.ToArray(attributes.Count));
|
||||
return string.Join(" ", attributes.ToArray());
|
||||
}
|
||||
|
||||
if (Type == MediaStreamType.Subtitle)
|
||||
|
@ -154,7 +155,7 @@ namespace MediaBrowser.Model.Entities
|
|||
attributes.Add("Forced");
|
||||
}
|
||||
|
||||
string name = string.Join(" ", attributes.ToArray(attributes.Count));
|
||||
string name = string.Join(" ", attributes.ToArray());
|
||||
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// TODO: @bond Remove
|
||||
namespace MediaBrowser.Model.Extensions
|
||||
{
|
||||
// MoreLINQ - Extensions to LINQ to Objects
|
||||
|
@ -42,19 +43,6 @@ namespace MediaBrowser.Model.Extensions
|
|||
return source.DistinctBy(keySelector, null);
|
||||
}
|
||||
|
||||
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source, int count)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (count < 0) throw new ArgumentOutOfRangeException("count");
|
||||
var array = new TSource[count];
|
||||
int i = 0;
|
||||
foreach (var item in source)
|
||||
{
|
||||
array[i++] = item;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all distinct elements of the given source, where "distinctness"
|
||||
/// is determined via a projection and the specified comparer for the projected type.
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.Services;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Model.Services
|
||||
{
|
||||
|
@ -586,7 +584,7 @@ namespace MediaBrowser.Model.Services
|
|||
WriteCharBytes(bytes, ch, e);
|
||||
}
|
||||
|
||||
byte[] buf = bytes.ToArray(bytes.Count);
|
||||
byte[] buf = bytes.ToArray();
|
||||
bytes = null;
|
||||
return e.GetString(buf, 0, buf.Length);
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Model.Services
|
||||
{
|
||||
|
@ -221,7 +220,7 @@ namespace MediaBrowser.Model.Services
|
|||
|
||||
public override String ToString()
|
||||
{
|
||||
var vals = this.Select(GetQueryStringValue).ToArray(this.Count);
|
||||
var vals = this.Select(GetQueryStringValue).ToArray();
|
||||
|
||||
return string.Join("&", vals);
|
||||
}
|
||||
|
|
|
@ -551,7 +551,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
{
|
||||
list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension));
|
||||
}
|
||||
return list.ToArray(list.Count);
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
if (type == ImageType.Primary)
|
||||
|
|
|
@ -522,7 +522,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
Type = MetadataPluginType.SubtitleFetcher
|
||||
}));
|
||||
|
||||
summary.Plugins = pluginList.ToArray(pluginList.Count);
|
||||
summary.Plugins = pluginList.ToArray();
|
||||
|
||||
var supportedImageTypes = imageProviders.OfType<IRemoteImageProvider>()
|
||||
.SelectMany(i => i.GetSupportedImages(dummy))
|
||||
|
@ -1160,4 +1160,4 @@ namespace MediaBrowser.Providers.Manager
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace MediaBrowser.Providers.Movies
|
|||
movie.ProductionLocations = movieData
|
||||
.production_countries
|
||||
.Select(i => i.name)
|
||||
.ToArray(movieData.production_countries.Count);
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
movie.SetProviderId(MetadataProviders.Tmdb, movieData.id.ToString(_usCulture));
|
||||
|
|
|
@ -279,7 +279,7 @@ namespace MediaBrowser.Providers.Movies
|
|||
languages.Add("en");
|
||||
}
|
||||
|
||||
return string.Join(",", languages.ToArray(languages.Count));
|
||||
return string.Join(",", languages.ToArray());
|
||||
}
|
||||
|
||||
public static string NormalizeLanguage(string language)
|
||||
|
|
|
@ -17,7 +17,6 @@ using System.Threading.Tasks;
|
|||
using System.Xml;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Xml;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
|
@ -846,4 +845,4 @@ namespace MediaBrowser.Providers.Music
|
|||
public int throttleMs { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ namespace MediaBrowser.Providers.TV
|
|||
|
||||
if (seriesInfo.networks != null)
|
||||
{
|
||||
series.Studios = seriesInfo.networks.Select(i => i.name).ToArray(seriesInfo.networks.Count);
|
||||
series.Studios = seriesInfo.networks.Select(i => i.name).ToArray();
|
||||
}
|
||||
|
||||
if (seriesInfo.genres != null)
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace Mono.Nat.Pmp
|
|||
|
||||
try
|
||||
{
|
||||
byte[] buffer = package.ToArray(package.Count);
|
||||
byte[] buffer = package.ToArray();
|
||||
int attempt = 0;
|
||||
int delay = PmpConstants.RetryDelay;
|
||||
|
||||
|
|
110
build-jellyfin.ps1
Normal file
110
build-jellyfin.ps1
Normal file
|
@ -0,0 +1,110 @@
|
|||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$InstallFFMPEG,
|
||||
[switch]$InstallNSSM,
|
||||
[switch]$GenerateZip,
|
||||
[string]$InstallLocation = "$Env:AppData/Jellyfin-Server/",
|
||||
[ValidateSet('Debug','Release')][string]$BuildType = 'Release',
|
||||
[ValidateSet('Quiet','Minimal', 'Normal')][string]$DotNetVerbosity = 'Minimal',
|
||||
[ValidateSet('win','win7', 'win8','win81','win10')][string]$WindowsVersion = 'win',
|
||||
[ValidateSet('x64','x86', 'arm', 'arm64')][string]$Architecture = 'x64'
|
||||
)
|
||||
|
||||
#PowershellCore and *nix check to make determine which temp dir to use.
|
||||
if(($PSVersionTable.PSEdition -eq 'Core') -and (-not $IsWindows)){
|
||||
$TempDir = mktemp -d
|
||||
}else{
|
||||
$TempDir = $env:Temp
|
||||
}
|
||||
|
||||
function Build-JellyFin {
|
||||
if(($Architecture -eq 'arm64') -and ($WindowsVersion -ne 'win10')){
|
||||
Write-Error "arm64 only supported with Windows10 Version"
|
||||
exit
|
||||
}
|
||||
if(($Architecture -eq 'arm') -and ($WindowsVersion -notin @('win10','win81','win8'))){
|
||||
Write-Error "arm only supported with Windows 8 or higher"
|
||||
exit
|
||||
}
|
||||
dotnet publish -c $BuildType -r "$windowsversion-$Architecture" MediaBrowser.sln -o $InstallLocation -v $DotNetVerbosity
|
||||
}
|
||||
|
||||
function Install-FFMPEG {
|
||||
param(
|
||||
[string]$InstallLocation,
|
||||
[string]$Architecture
|
||||
)
|
||||
Write-Verbose "Checking Architecture"
|
||||
if($Architecture -notin @('x86','x64')){
|
||||
Write-Warning "No builds available for your selected architecture of $Architecture"
|
||||
Write-Warning "FFMPEG will not be installed"
|
||||
}elseif($Architecture -eq 'x64'){
|
||||
Write-Verbose "Downloading 64 bit FFMPEG"
|
||||
Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-4.1-win64-static.zip -UseBasicParsing -OutFile "$tempdir/fmmpeg.zip" | Write-Verbose
|
||||
}else{
|
||||
Write-Verbose "Downloading 32 bit FFMPEG"
|
||||
Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-4.1-win32-static.zip -UseBasicParsing -OutFile "$tempdir/fmmpeg.zip" | Write-Verbose
|
||||
}
|
||||
|
||||
Expand-Archive "$tempdir/fmmpeg.zip" -DestinationPath "$tempdir/ffmpeg/" | Write-Verbose
|
||||
if($Architecture -eq 'x64'){
|
||||
Write-Verbose "Copying Binaries to Jellyfin location"
|
||||
Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.1-win64-static/bin" | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
|
||||
}
|
||||
}else{
|
||||
Write-Verbose "Copying Binaries to Jellyfin location"
|
||||
Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.1-win32-static/bin" | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
|
||||
}
|
||||
}
|
||||
Remove-Item "$tempdir/ffmpeg/" -Recurse -Force -ErrorAction Continue | Write-Verbose
|
||||
Remove-Item "$tempdir/fmmpeg.zip" -Force -ErrorAction Continue | Write-Verbose
|
||||
}
|
||||
|
||||
function Install-NSSM {
|
||||
param(
|
||||
[string]$InstallLocation,
|
||||
[string]$Architecture
|
||||
)
|
||||
Write-Verbose "Checking Architecture"
|
||||
if($Architecture -notin @('x86','x64')){
|
||||
Write-Warning "No builds available for your selected architecture of $Architecture"
|
||||
Write-Warning "NSSM will not be installed"
|
||||
}else{
|
||||
Write-Verbose "Downloading NSSM"
|
||||
Invoke-WebRequest -Uri https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip -UseBasicParsing -OutFile "$tempdir/nssm.zip" | Write-Verbose
|
||||
}
|
||||
|
||||
Expand-Archive "$tempdir/nssm.zip" -DestinationPath "$tempdir/nssm/" | Write-Verbose
|
||||
if($Architecture -eq 'x64'){
|
||||
Write-Verbose "Copying Binaries to Jellyfin location"
|
||||
Get-ChildItem "$tempdir/nssm/nssm-2.24-101-g897c7ad/win64" | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
|
||||
}
|
||||
}else{
|
||||
Write-Verbose "Copying Binaries to Jellyfin location"
|
||||
Get-ChildItem "$tempdir/nssm/nssm-2.24-101-g897c7ad/win32" | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
|
||||
}
|
||||
}
|
||||
Remove-Item "$tempdir/nssm/" -Recurse -Force -ErrorAction Continue | Write-Verbose
|
||||
Remove-Item "$tempdir/nssm.zip" -Force -ErrorAction Continue | Write-Verbose
|
||||
}
|
||||
|
||||
Write-Verbose "Starting Build Process: Selected Environment is $WindowsVersion-$Architecture"
|
||||
Build-JellyFin
|
||||
if($InstallFFMPEG.IsPresent -or ($InstallFFMPEG -eq $true)){
|
||||
Write-Verbose "Starting FFMPEG Install"
|
||||
Install-FFMPEG $InstallLocation $Architecture
|
||||
}
|
||||
if($InstallNSSM.IsPresent -or ($InstallNSSM -eq $true)){
|
||||
Write-Verbose "Starting NSSM Install"
|
||||
Install-NSSM $InstallLocation $Architecture
|
||||
}
|
||||
Copy-Item .\install-jellyfin.ps1 $InstallLocation\install-jellyfin.ps1
|
||||
Copy-Item .\installjellyfin.bat $InstallLocation\installjellyfin.bat
|
||||
if($GenerateZip.IsPresent -or ($GenerateZip -eq $true)){
|
||||
Compress-Archive -Path $InstallLocation -DestinationPath "$InstallLocation/jellyfin.zip" -Force
|
||||
}
|
||||
Write-Verbose "Finished"
|
7
debian/changelog
vendored
7
debian/changelog
vendored
|
@ -1,3 +1,10 @@
|
|||
jellyfin (3.5.2-5) unstable; urgency=medium
|
||||
|
||||
* Fully GPL'd release - remove tainted code from MediaBrowser.Common
|
||||
* Several code cleanups and tweaks
|
||||
|
||||
-- Joshua Boniface <joshua@boniface.me> Fri, 28 Dec 2018 10:26:30 -0500
|
||||
|
||||
jellyfin (3.5.2-4) unstable; urgency=medium
|
||||
|
||||
* Correct manifest.json bug and vdpau
|
||||
|
|
4
debian/jellyfin.service
vendored
4
debian/jellyfin.service
vendored
|
@ -7,8 +7,8 @@ Type = simple
|
|||
EnvironmentFile = /etc/default/jellyfin
|
||||
User = jellyfin
|
||||
ExecStart = /usr/bin/jellyfin -programdata ${JELLYFIN_DATA} -restartpath ${JELLYFIN_RESTART_SCRIPT} ${JELLYFIN_ADD_OPTS}
|
||||
Restart = on-abort
|
||||
TimeoutSec = 20
|
||||
Restart = on-failure
|
||||
TimeoutSec = 15
|
||||
|
||||
[Install]
|
||||
WantedBy = multi-user.target
|
||||
|
|
3
debian/rules
vendored
3
debian/rules
vendored
|
@ -2,6 +2,7 @@
|
|||
CONFIG := Release
|
||||
TERM := xterm
|
||||
SHELL := /bin/bash
|
||||
DOTNETRUNTIME := linux-x64
|
||||
export DH_VERBOSE=1
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
||||
|
@ -15,7 +16,7 @@ override_dh_auto_test:
|
|||
override_dh_clistrip:
|
||||
|
||||
override_dh_auto_build:
|
||||
dotnet publish --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime linux-x64
|
||||
dotnet publish --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime $(DOTNETRUNTIME)
|
||||
|
||||
override_dh_auto_clean:
|
||||
dotnet clean -maxcpucount:1 --configuration $(CONFIG) || true
|
||||
|
|
460
install-jellyfin.ps1
Normal file
460
install-jellyfin.ps1
Normal file
|
@ -0,0 +1,460 @@
|
|||
[CmdletBinding()]
|
||||
|
||||
param(
|
||||
[Switch]$Quiet,
|
||||
[Switch]$InstallAsService,
|
||||
[pscredential]$ServiceUser,
|
||||
[switch]$CreateDesktopShorcut,
|
||||
[switch]$LaunchJellyfin,
|
||||
[switch]$MigrateEmbyLibrary,
|
||||
[string]$InstallLocation,
|
||||
[string]$EmbyLibraryLocation,
|
||||
[string]$JellyfinLibraryLocation
|
||||
)
|
||||
<# This form was created using POSHGUI.com a free online gui designer for PowerShell
|
||||
.NAME
|
||||
Install-Jellyfin
|
||||
#>
|
||||
|
||||
#This doesn't need to be used by default anymore, but I am keeping it in as a function for future use.
|
||||
function Elevate-Window {
|
||||
# Get the ID and security principal of the current user account
|
||||
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
||||
|
||||
# Get the security principal for the Administrator role
|
||||
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
|
||||
# Check to see if we are currently running "as Administrator"
|
||||
if ($myWindowsPrincipal.IsInRole($adminRole))
|
||||
{
|
||||
# We are running "as Administrator" - so change the title and background color to indicate this
|
||||
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
|
||||
$Host.UI.RawUI.BackgroundColor = "DarkBlue"
|
||||
clear-host
|
||||
}
|
||||
else
|
||||
{
|
||||
# We are not running "as Administrator" - so relaunch as administrator
|
||||
|
||||
# Create a new process object that starts PowerShell
|
||||
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
|
||||
|
||||
# Specify the current script path and name as a parameter
|
||||
$newProcess.Arguments = $myInvocation.MyCommand.Definition;
|
||||
|
||||
# Indicate that the process should be elevated
|
||||
$newProcess.Verb = "runas";
|
||||
|
||||
# Start the new process
|
||||
[System.Diagnostics.Process]::Start($newProcess);
|
||||
|
||||
# Exit from the current, unelevated, process
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
#FIXME The install methods should be a function that takes all the params, the quiet flag should be a paramset
|
||||
|
||||
if($Quiet.IsPresent -or $Quiet -eq $true){
|
||||
if([string]::IsNullOrEmpty($JellyfinLibraryLocation)){
|
||||
$Script:JellyfinDataDir = "$env:AppData\jellyfin\"
|
||||
}else{
|
||||
$Script:JellyfinDataDir = $JellyfinLibraryLocation
|
||||
}
|
||||
if([string]::IsNullOrEmpty($InstallLocation)){
|
||||
$Script:DefaultJellyfinInstallDirectory = "$env:Appdata\jellyfin\"
|
||||
}else{
|
||||
$Script:DefaultJellyfinInstallDirectory = $InstallLocation
|
||||
}
|
||||
|
||||
if([string]::IsNullOrEmpty($EmbyLibraryLocation)){
|
||||
$Script:defaultEmbyDataDir = "$env:Appdata\Emby-Server\data\"
|
||||
}else{
|
||||
$Script:defaultEmbyDataDir = $EmbyLibraryLocation
|
||||
}
|
||||
|
||||
if($InstallAsService.IsPresent -or $InstallAsService -eq $true){
|
||||
$Script:InstallAsService = $true
|
||||
}else{$Script:InstallAsService = $false}
|
||||
if($null -eq $ServiceUser){
|
||||
$Script:InstallServiceAsUser = $false
|
||||
}else{
|
||||
$Script:InstallServiceAsUser = $true
|
||||
$Script:UserCredentials = $ServiceUser
|
||||
$Script:JellyfinDataDir = "C:\Users\$($Script:UserCredentials.UserName)\Appdata\Roaming\jellyfin\"}
|
||||
if($CreateDesktopShorcut.IsPresent -or $CreateDesktopShorcut -eq $true) {$Script:CreateShortcut = $true}else{$Script:CreateShortcut = $false}
|
||||
if($MigrateEmbyLibrary.IsPresent -or $MigrateEmbyLibrary -eq $true){$Script:MigrateLibrary = $true}else{$Script:MigrateLibrary = $false}
|
||||
if($LaunchJellyfin.IsPresent -or $LaunchJellyfin -eq $true){$Script:StartJellyfin = $true}else{$Script:StartJellyfin = $false}
|
||||
|
||||
if(-not (Test-Path $Script:DefaultJellyfinInstallDirectory)){
|
||||
mkdir $Script:DefaultJellyfinInstallDirectory
|
||||
}
|
||||
Copy-Item -Path $PSScriptRoot/* -DestinationPath "$Script:DefaultJellyfinInstallDirectory/" -Force -Recurse
|
||||
if($Script:InstallAsService){
|
||||
if($Script:InstallServiceAsUser){
|
||||
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
|
||||
Start-Sleep -Milliseconds 500
|
||||
&sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)"
|
||||
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
|
||||
}else{
|
||||
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
|
||||
Start-Sleep -Milliseconds 500
|
||||
#&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin ObjectName $Script:UserCredentials.UserName $Script:UserCredentials.GetNetworkCredential().Password
|
||||
#Set-Service -Name Jellyfin -Credential $Script:UserCredentials
|
||||
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
|
||||
}
|
||||
}
|
||||
if($Script:MigrateLibrary){
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/config -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/cache -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/data -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/metadata -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/root -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
}
|
||||
if($Script:CreateShortcut){
|
||||
$WshShell = New-Object -comObject WScript.Shell
|
||||
$Shortcut = $WshShell.CreateShortcut("$Home\Desktop\Jellyfin.lnk")
|
||||
$Shortcut.TargetPath = "$Script:DefaultJellyfinInstallDirectory\jellyfin.exe"
|
||||
$Shortcut.Save()
|
||||
}
|
||||
if($Script:StartJellyfin){
|
||||
if($Script:InstallAsService){
|
||||
Get-Service Jellyfin | Start-Service
|
||||
}else{
|
||||
Start-Process -FilePath $Script:DefaultJellyfinInstallDirectory\jellyfin.exe -PassThru
|
||||
}
|
||||
}
|
||||
}else{
|
||||
|
||||
}
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||
|
||||
$Script:JellyFinDataDir = "$env:AppData\jellyfin\"
|
||||
$Script:DefaultJellyfinInstallDirectory = "$env:Appdata\jellyfin\"
|
||||
$Script:defaultEmbyDataDir = "$env:Appdata\Emby-Server\"
|
||||
$Script:InstallAsService = $False
|
||||
$Script:InstallServiceAsUser = $false
|
||||
$Script:CreateShortcut = $false
|
||||
$Script:MigrateLibrary = $false
|
||||
$Script:StartJellyfin = $false
|
||||
|
||||
function InstallJellyfin {
|
||||
Write-Host "Install as service: $Script:InstallAsService"
|
||||
Write-Host "Install as serviceuser: $Script:InstallServiceAsUser"
|
||||
Write-Host "Create Shortcut: $Script:CreateShortcut"
|
||||
Write-Host "MigrateLibrary: $Script:MigrateLibrary"
|
||||
$GUIElementsCollection | ForEach-Object {
|
||||
$_.Enabled = $false
|
||||
}
|
||||
Write-Host "Making Jellyfin directory"
|
||||
$ProgressBar.Minimum = 1
|
||||
$ProgressBar.Maximum = 100
|
||||
$ProgressBar.Value = 1
|
||||
if($Script:DefaultJellyfinInstallDirectory -ne $InstallLocationBox.Text){
|
||||
Write-Host "Custom Install Location Chosen: $($InstallLocationBox.Text)"
|
||||
$Script:DefaultJellyfinInstallDirectory = $InstallLocationBox.Text
|
||||
}
|
||||
if($Script:JellyfinDataDir -ne $CustomLibraryBox.Text){
|
||||
Write-Host "Custom Library Location Chosen: $($CustomLibraryBox.Text)"
|
||||
$Script:JellyfinDataDir = $CustomLibraryBox.Text
|
||||
}
|
||||
if(-not (Test-Path $Script:DefaultJellyfinInstallDirectory)){
|
||||
mkdir $Script:DefaultJellyfinInstallDirectory
|
||||
}
|
||||
Write-Host "Copying Jellyfin Data"
|
||||
$progressbar.Value = 10
|
||||
Copy-Item -Path $PSScriptRoot/* -Destination $Script:DefaultJellyfinInstallDirectory/ -Force -Recurse
|
||||
Write-Host "Finished Copying"
|
||||
$ProgressBar.Value = 50
|
||||
if($Script:InstallAsService){
|
||||
if($Script:InstallServiceAsUser){
|
||||
Write-Host "Installing Service as user $($Script:UserCredentials.UserName)"
|
||||
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
|
||||
Start-Sleep -Milliseconds 2000
|
||||
&sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)"
|
||||
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
|
||||
}else{
|
||||
Write-Host "Installing Service as LocalSystem"
|
||||
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
|
||||
Start-Sleep -Milliseconds 2000
|
||||
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
|
||||
}
|
||||
}
|
||||
$progressbar.Value = 60
|
||||
if($Script:MigrateLibrary){
|
||||
if($Script:defaultEmbyDataDir -ne $LibraryLocationBox.Text){
|
||||
Write-Host "Custom location defined for emby library: $($LibraryLocationBox.Text)"
|
||||
$Script:defaultEmbyDataDir = $LibraryLocationBox.Text
|
||||
}
|
||||
Write-Host "Copying emby library from $Script:defaultEmbyDataDir to $Script:JellyFinDataDir"
|
||||
Write-Host "This could take a while depending on the size of your library. Please be patient"
|
||||
Write-Host "Copying config"
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/config -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
Write-Host "Copying cache"
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/cache -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
Write-Host "Copying data"
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/data -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
Write-Host "Copying metadata"
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/metadata -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
Write-Host "Copying root dir"
|
||||
Copy-Item -Path $Script:defaultEmbyDataDir/root -Destination $Script:JellyfinDataDir -force -Recurse
|
||||
}
|
||||
$progressbar.Value = 80
|
||||
if($Script:CreateShortcut){
|
||||
Write-Host "Creating Shortcut"
|
||||
$WshShell = New-Object -comObject WScript.Shell
|
||||
$Shortcut = $WshShell.CreateShortcut("$Home\Desktop\Jellyfin.lnk")
|
||||
$Shortcut.TargetPath = "$Script:DefaultJellyfinInstallDirectory\jellyfin.exe"
|
||||
$Shortcut.Save()
|
||||
}
|
||||
$ProgressBar.Value = 90
|
||||
if($Script:StartJellyfin){
|
||||
if($Script:InstallAsService){
|
||||
Write-Host "Starting Jellyfin Service"
|
||||
Get-Service Jellyfin | Start-Service
|
||||
}else{
|
||||
Write-Host "Starting Jellyfin"
|
||||
Start-Process -FilePath $Script:DefaultJellyfinInstallDirectory\jellyfin.exe -PassThru
|
||||
}
|
||||
}
|
||||
$progressbar.Value = 100
|
||||
Write-Host Finished
|
||||
$wshell = New-Object -ComObject Wscript.Shell
|
||||
$wshell.Popup("Operation Completed",0,"Done",0x1)
|
||||
$InstallForm.Close()
|
||||
}
|
||||
function ServiceBoxCheckChanged {
|
||||
if($InstallAsServiceCheck.Checked){
|
||||
$Script:InstallAsService = $true
|
||||
$ServiceUserLabel.Visible = $true
|
||||
$ServiceUserLabel.Enabled = $true
|
||||
$ServiceUserBox.Visible = $true
|
||||
$ServiceUserBox.Enabled = $true
|
||||
}else{
|
||||
$Script:InstallAsService = $false
|
||||
$ServiceUserLabel.Visible = $false
|
||||
$ServiceUserLabel.Enabled = $false
|
||||
$ServiceUserBox.Visible = $false
|
||||
$ServiceUserBox.Enabled = $false
|
||||
}
|
||||
}
|
||||
function UserSelect {
|
||||
if($ServiceUserBox.Text -eq 'Local System')
|
||||
{
|
||||
$Script:InstallServiceAsUser = $false
|
||||
$Script:UserCredentials = $null
|
||||
$ServiceUserBox.Items.RemoveAt(1)
|
||||
$ServiceUserBox.Items.Add("Custom User")
|
||||
}elseif($ServiceUserBox.Text -eq 'Custom User'){
|
||||
$Script:InstallServiceAsUser = $true
|
||||
$Script:UserCredentials = Get-Credential -Message "Please enter the credentials of the user you with to run Jellyfin Service as" -UserName $env:USERNAME
|
||||
$ServiceUserBox.Items[1] = "$($Script:UserCredentials.UserName)"
|
||||
}
|
||||
}
|
||||
function CreateShortcutBoxCheckChanged {
|
||||
if($CreateShortcutCheck.Checked){
|
||||
$Script:CreateShortcut = $true
|
||||
}else{
|
||||
$Script:CreateShortcut = $False
|
||||
}
|
||||
}
|
||||
function StartJellyFinBoxCheckChanged {
|
||||
if($StartProgramCheck.Checked){
|
||||
$Script:StartJellyfin = $true
|
||||
}else{
|
||||
$Script:StartJellyfin = $false
|
||||
}
|
||||
}
|
||||
|
||||
function CustomLibraryCheckChanged {
|
||||
if($CustomLibraryCheck.Checked){
|
||||
$Script:UseCustomLibrary = $true
|
||||
$CustomLibraryBox.Enabled = $true
|
||||
}else{
|
||||
$Script:UseCustomLibrary = $false
|
||||
$CustomLibraryBox.Enabled = $false
|
||||
}
|
||||
}
|
||||
|
||||
function MigrateLibraryCheckboxChanged {
|
||||
|
||||
if($MigrateLibraryCheck.Checked){
|
||||
$Script:MigrateLibrary = $true
|
||||
$LibraryMigrationLabel.Visible = $true
|
||||
$LibraryMigrationLabel.Enabled = $true
|
||||
$LibraryLocationBox.Visible = $true
|
||||
$LibraryLocationBox.Enabled = $true
|
||||
}else{
|
||||
$Script:MigrateLibrary = $false
|
||||
$LibraryMigrationLabel.Visible = $false
|
||||
$LibraryMigrationLabel.Enabled = $false
|
||||
$LibraryLocationBox.Visible = $false
|
||||
$LibraryLocationBox.Enabled = $false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region begin GUI{
|
||||
|
||||
$InstallForm = New-Object system.Windows.Forms.Form
|
||||
$InstallForm.ClientSize = '320,240'
|
||||
$InstallForm.text = "Terrible Jellyfin Installer"
|
||||
$InstallForm.TopMost = $false
|
||||
|
||||
$GUIElementsCollection = @()
|
||||
|
||||
$InstallButton = New-Object system.Windows.Forms.Button
|
||||
$InstallButton.text = "Install"
|
||||
$InstallButton.width = 60
|
||||
$InstallButton.height = 30
|
||||
$InstallButton.location = New-Object System.Drawing.Point(5,5)
|
||||
$InstallButton.Font = 'Microsoft Sans Serif,10'
|
||||
$GUIElementsCollection += $InstallButton
|
||||
|
||||
$ProgressBar = New-Object system.Windows.Forms.ProgressBar
|
||||
$ProgressBar.width = 245
|
||||
$ProgressBar.height = 30
|
||||
$ProgressBar.location = New-Object System.Drawing.Point(70,5)
|
||||
|
||||
$InstallLocationLabel = New-Object system.Windows.Forms.Label
|
||||
$InstallLocationLabel.text = "Install Location"
|
||||
$InstallLocationLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
|
||||
$InstallLocationLabel.AutoSize = $true
|
||||
$InstallLocationLabel.width = 100
|
||||
$InstallLocationLabel.height = 20
|
||||
$InstallLocationLabel.location = New-Object System.Drawing.Point(5,50)
|
||||
$InstallLocationLabel.Font = 'Microsoft Sans Serif,10'
|
||||
$GUIElementsCollection += $InstallLocationLabel
|
||||
|
||||
$InstallLocationBox = New-Object system.Windows.Forms.TextBox
|
||||
$InstallLocationBox.multiline = $false
|
||||
$InstallLocationBox.width = 205
|
||||
$InstallLocationBox.height = 20
|
||||
$InstallLocationBox.location = New-Object System.Drawing.Point(110,50)
|
||||
$InstallLocationBox.Text = $Script:DefaultJellyfinInstallDirectory
|
||||
$InstallLocationBox.Font = 'Microsoft Sans Serif,10'
|
||||
$GUIElementsCollection += $InstallLocationBox
|
||||
|
||||
$CustomLibraryCheck = New-Object system.Windows.Forms.CheckBox
|
||||
$CustomLibraryCheck.text = "Custom Library Location:"
|
||||
$CustomLibraryCheck.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
|
||||
$CustomLibraryCheck.AutoSize = $false
|
||||
$CustomLibraryCheck.width = 180
|
||||
$CustomLibraryCheck.height = 20
|
||||
$CustomLibraryCheck.location = New-Object System.Drawing.Point(5,75)
|
||||
$CustomLibraryCheck.Font = 'Microsoft Sans Serif,10'
|
||||
$GUIElementsCollection += $CustomLibraryCheck
|
||||
|
||||
$CustomLibraryBox = New-Object system.Windows.Forms.TextBox
|
||||
$CustomLibraryBox.multiline = $false
|
||||
$CustomLibraryBox.width = 130
|
||||
$CustomLibraryBox.height = 20
|
||||
$CustomLibraryBox.location = New-Object System.Drawing.Point(185,75)
|
||||
$CustomLibraryBox.Text = $Script:JellyFinDataDir
|
||||
$CustomLibraryBox.Font = 'Microsoft Sans Serif,10'
|
||||
$CustomLibraryBox.Enabled = $false
|
||||
$GUIElementsCollection += $CustomLibraryBox
|
||||
|
||||
$InstallAsServiceCheck = New-Object system.Windows.Forms.CheckBox
|
||||
$InstallAsServiceCheck.text = "Install as Service"
|
||||
$InstallAsServiceCheck.AutoSize = $false
|
||||
$InstallAsServiceCheck.width = 140
|
||||
$InstallAsServiceCheck.height = 20
|
||||
$InstallAsServiceCheck.location = New-Object System.Drawing.Point(5,125)
|
||||
$InstallAsServiceCheck.Font = 'Microsoft Sans Serif,10'
|
||||
$GUIElementsCollection += $InstallAsServiceCheck
|
||||
|
||||
$ServiceUserLabel = New-Object system.Windows.Forms.Label
|
||||
$ServiceUserLabel.text = "Run Service As:"
|
||||
$ServiceUserLabel.AutoSize = $true
|
||||
$ServiceUserLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
|
||||
$ServiceUserLabel.width = 100
|
||||
$ServiceUserLabel.height = 20
|
||||
$ServiceUserLabel.location = New-Object System.Drawing.Point(15,145)
|
||||
$ServiceUserLabel.Font = 'Microsoft Sans Serif,10'
|
||||
$ServiceUserLabel.Visible = $false
|
||||
$ServiceUserLabel.Enabled = $false
|
||||
$GUIElementsCollection += $ServiceUserLabel
|
||||
|
||||
$ServiceUserBox = New-Object system.Windows.Forms.ComboBox
|
||||
$ServiceUserBox.text = "Run Service As"
|
||||
$ServiceUserBox.width = 195
|
||||
$ServiceUserBox.height = 20
|
||||
@('Local System','Custom User') | ForEach-Object {[void] $ServiceUserBox.Items.Add($_)}
|
||||
$ServiceUserBox.location = New-Object System.Drawing.Point(120,145)
|
||||
$ServiceUserBox.Font = 'Microsoft Sans Serif,10'
|
||||
$ServiceUserBox.Visible = $false
|
||||
$ServiceUserBox.Enabled = $false
|
||||
$ServiceUserBox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList
|
||||
$GUIElementsCollection += $ServiceUserBox
|
||||
|
||||
$MigrateLibraryCheck = New-Object system.Windows.Forms.CheckBox
|
||||
$MigrateLibraryCheck.text = "Import Emby Library"
|
||||
$MigrateLibraryCheck.AutoSize = $false
|
||||
$MigrateLibraryCheck.width = 160
|
||||
$MigrateLibraryCheck.height = 20
|
||||
$MigrateLibraryCheck.location = New-Object System.Drawing.Point(5,170)
|
||||
$MigrateLibraryCheck.Font = 'Microsoft Sans Serif,10'
|
||||
$GUIElementsCollection += $MigrateLibraryCheck
|
||||
|
||||
$LibraryMigrationLabel = New-Object system.Windows.Forms.Label
|
||||
$LibraryMigrationLabel.text = "Emby Library Path"
|
||||
$LibraryMigrationLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
|
||||
$LibraryMigrationLabel.AutoSize = $false
|
||||
$LibraryMigrationLabel.width = 120
|
||||
$LibraryMigrationLabel.height = 20
|
||||
$LibraryMigrationLabel.location = New-Object System.Drawing.Point(15,190)
|
||||
$LibraryMigrationLabel.Font = 'Microsoft Sans Serif,10'
|
||||
$LibraryMigrationLabel.Visible = $false
|
||||
$LibraryMigrationLabel.Enabled = $false
|
||||
$GUIElementsCollection += $LibraryMigrationLabel
|
||||
|
||||
$LibraryLocationBox = New-Object system.Windows.Forms.TextBox
|
||||
$LibraryLocationBox.multiline = $false
|
||||
$LibraryLocationBox.width = 175
|
||||
$LibraryLocationBox.height = 20
|
||||
$LibraryLocationBox.location = New-Object System.Drawing.Point(140,190)
|
||||
$LibraryLocationBox.Text = $Script:defaultEmbyDataDir
|
||||
$LibraryLocationBox.Font = 'Microsoft Sans Serif,10'
|
||||
$LibraryLocationBox.Visible = $false
|
||||
$LibraryLocationBox.Enabled = $false
|
||||
$GUIElementsCollection += $LibraryLocationBox
|
||||
|
||||
$CreateShortcutCheck = New-Object system.Windows.Forms.CheckBox
|
||||
$CreateShortcutCheck.text = "Desktop Shortcut"
|
||||
$CreateShortcutCheck.AutoSize = $false
|
||||
$CreateShortcutCheck.width = 150
|
||||
$CreateShortcutCheck.height = 20
|
||||
$CreateShortcutCheck.location = New-Object System.Drawing.Point(5,215)
|
||||
$CreateShortcutCheck.Font = 'Microsoft Sans Serif,10'
|
||||
$GUIElementsCollection += $CreateShortcutCheck
|
||||
|
||||
$StartProgramCheck = New-Object system.Windows.Forms.CheckBox
|
||||
$StartProgramCheck.text = "Start Jellyfin"
|
||||
$StartProgramCheck.AutoSize = $false
|
||||
$StartProgramCheck.width = 160
|
||||
$StartProgramCheck.height = 20
|
||||
$StartProgramCheck.location = New-Object System.Drawing.Point(160,215)
|
||||
$StartProgramCheck.Font = 'Microsoft Sans Serif,10'
|
||||
$GUIElementsCollection += $StartProgramCheck
|
||||
|
||||
$InstallForm.controls.AddRange($GUIElementsCollection)
|
||||
$InstallForm.Controls.Add($ProgressBar)
|
||||
|
||||
#region gui events {
|
||||
$InstallButton.Add_Click({ InstallJellyfin })
|
||||
$CustomLibraryCheck.Add_CheckedChanged({CustomLibraryCheckChanged})
|
||||
$InstallAsServiceCheck.Add_CheckedChanged({ServiceBoxCheckChanged})
|
||||
$ServiceUserBox.Add_SelectedValueChanged({ UserSelect })
|
||||
$MigrateLibraryCheck.Add_CheckedChanged({MigrateLibraryCheckboxChanged})
|
||||
$CreateShortcutCheck.Add_CheckedChanged({CreateShortcutBoxCheckChanged})
|
||||
$StartProgramCheck.Add_CheckedChanged({StartJellyFinBoxCheckChanged})
|
||||
#endregion events }
|
||||
|
||||
#endregion GUI }
|
||||
|
||||
|
||||
[void]$InstallForm.ShowDialog()
|
1
install.bat
Normal file
1
install.bat
Normal file
|
@ -0,0 +1 @@
|
|||
powershell.exe -executionpolicy Bypass -file install-jellyfin.ps1
|
22
new-file-header.txt
Normal file
22
new-file-header.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
### This header should be used to start new files.
|
||||
### It provides an explicit per-file license reference that should be present on all new files.
|
||||
### To use this header, delete these lines and the following empty line, modify <filename> to
|
||||
### the proper full path, and then add new code following the header and a single empty line.
|
||||
|
||||
// <filename>
|
||||
// Part of the Jellyfin project (https://jellyfin.media)
|
||||
//
|
||||
// All copyright belongs to the Jellyfin contributors; a full list can
|
||||
// be found in the file CONTRIBUTORS.md
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
Loading…
Reference in New Issue
Block a user