commit
063fd56832
|
@ -74,6 +74,34 @@ namespace MediaBrowser.Api.Library
|
||||||
public bool RememberCorrection { get; set; }
|
public bool RememberCorrection { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/Library/FileOrganizationSmartMatch", "GET", Summary = "Gets smart match entries")]
|
||||||
|
public class GetSmartMatchInfos : IReturn<QueryResult<SmartMatchInfo>>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Skips over a given number of items within the results. Use for paging.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The start index.</value>
|
||||||
|
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? StartIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of items to return
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The limit.</value>
|
||||||
|
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? Limit { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Library/FileOrganizationSmartMatch/{Id}/Delete", "POST", Summary = "Deletes a smart match entry")]
|
||||||
|
public class DeleteSmartMatchEntry
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "Id", Description = "Item ID", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "MatchString", Description = "SmartMatch String", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||||
|
public string MatchString { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Authenticated(Roles = "Admin")]
|
[Authenticated(Roles = "Admin")]
|
||||||
public class FileOrganizationService : BaseApiService
|
public class FileOrganizationService : BaseApiService
|
||||||
{
|
{
|
||||||
|
@ -130,5 +158,21 @@ namespace MediaBrowser.Api.Library
|
||||||
|
|
||||||
Task.WaitAll(task);
|
Task.WaitAll(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Get(GetSmartMatchInfos request)
|
||||||
|
{
|
||||||
|
var result = _iFileOrganizationService.GetSmartMatchInfos(new FileOrganizationResultQuery
|
||||||
|
{
|
||||||
|
Limit = request.Limit,
|
||||||
|
StartIndex = request.StartIndex
|
||||||
|
});
|
||||||
|
|
||||||
|
return ToOptimizedSerializedResultUsingCache(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Post(DeleteSmartMatchEntry request)
|
||||||
|
{
|
||||||
|
_iFileOrganizationService.DeleteSmartMatchEntry(request.Id, request.MatchString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,9 +305,8 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">The state.</param>
|
/// <param name="state">The state.</param>
|
||||||
/// <param name="videoCodec">The video codec.</param>
|
/// <param name="videoCodec">The video codec.</param>
|
||||||
/// <param name="isHls">if set to <c>true</c> [is HLS].</param>
|
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetVideoQualityParam(StreamState state, string videoCodec, bool isHls)
|
protected string GetVideoQualityParam(StreamState state, string videoCodec)
|
||||||
{
|
{
|
||||||
var param = string.Empty;
|
var param = string.Empty;
|
||||||
|
|
||||||
|
@ -385,7 +384,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
param = "-mbd 2";
|
param = "-mbd 2";
|
||||||
}
|
}
|
||||||
|
|
||||||
param += GetVideoBitrateParam(state, videoCodec, isHls);
|
param += GetVideoBitrateParam(state, videoCodec);
|
||||||
|
|
||||||
var framerate = GetFramerateParam(state);
|
var framerate = GetFramerateParam(state);
|
||||||
if (framerate.HasValue)
|
if (framerate.HasValue)
|
||||||
|
@ -1190,7 +1189,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
return bitrate;
|
return bitrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string GetVideoBitrateParam(StreamState state, string videoCodec, bool isHls)
|
protected string GetVideoBitrateParam(StreamState state, string videoCodec)
|
||||||
{
|
{
|
||||||
var bitrate = state.OutputVideoBitrate;
|
var bitrate = state.OutputVideoBitrate;
|
||||||
|
|
||||||
|
@ -1209,14 +1208,9 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
|
|
||||||
// h264
|
// h264
|
||||||
if (isHls)
|
return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
|
||||||
{
|
bitrate.Value.ToString(UsCulture),
|
||||||
return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
|
(bitrate.Value * 2).ToString(UsCulture));
|
||||||
bitrate.Value.ToString(UsCulture),
|
|
||||||
(bitrate.Value * 2).ToString(UsCulture));
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
|
@ -430,7 +430,7 @@ namespace MediaBrowser.Api.Playback.Dash
|
||||||
|
|
||||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
|
|
||||||
args += " " + GetVideoQualityParam(state, GetH264Encoder(state), true) + keyFrameArg;
|
args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg;
|
||||||
|
|
||||||
// Add resolution params, if specified
|
// Add resolution params, if specified
|
||||||
if (!hasGraphicalSubs)
|
if (!hasGraphicalSubs)
|
||||||
|
|
|
@ -822,7 +822,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
|
|
||||||
args += " " + GetVideoQualityParam(state, GetH264Encoder(state), true) + keyFrameArg;
|
args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg;
|
||||||
|
|
||||||
//args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
|
//args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
|
|
||||||
args += " " + GetVideoQualityParam(state, GetH264Encoder(state), true) + keyFrameArg;
|
args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg;
|
||||||
|
|
||||||
// Add resolution params, if specified
|
// Add resolution params, if specified
|
||||||
if (!hasGraphicalSubs)
|
if (!hasGraphicalSubs)
|
||||||
|
|
|
@ -166,7 +166,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
args += GetOutputSizeParam(state, videoCodec);
|
args += GetOutputSizeParam(state, videoCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
var qualityParam = GetVideoQualityParam(state, videoCodec, false);
|
var qualityParam = GetVideoQualityParam(state, videoCodec);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(qualityParam))
|
if (!string.IsNullOrEmpty(qualityParam))
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,5 +67,19 @@ namespace MediaBrowser.Controller.FileOrganization
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken);
|
Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of smart match entries
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <returns>IEnumerable{SmartMatchInfo}.</returns>
|
||||||
|
QueryResult<SmartMatchInfo> GetSmartMatchInfos(FileOrganizationResultQuery query);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a smart match entry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Id">Item Id.</param>
|
||||||
|
/// <param name="matchString">The match string to delete.</param>
|
||||||
|
void DeleteSmartMatchEntry(string Id, string matchString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -568,9 +568,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">The state.</param>
|
/// <param name="state">The state.</param>
|
||||||
/// <param name="videoCodec">The video codec.</param>
|
/// <param name="videoCodec">The video codec.</param>
|
||||||
/// <param name="isHls">if set to <c>true</c> [is HLS].</param>
|
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetVideoQualityParam(EncodingJob state, string videoCodec, bool isHls)
|
protected string GetVideoQualityParam(EncodingJob state, string videoCodec)
|
||||||
{
|
{
|
||||||
var param = string.Empty;
|
var param = string.Empty;
|
||||||
|
|
||||||
|
@ -648,7 +647,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
param = "-mbd 2";
|
param = "-mbd 2";
|
||||||
}
|
}
|
||||||
|
|
||||||
param += GetVideoBitrateParam(state, videoCodec, isHls);
|
param += GetVideoBitrateParam(state, videoCodec);
|
||||||
|
|
||||||
var framerate = GetFramerateParam(state);
|
var framerate = GetFramerateParam(state);
|
||||||
if (framerate.HasValue)
|
if (framerate.HasValue)
|
||||||
|
@ -718,7 +717,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return "-pix_fmt yuv420p " + param;
|
return "-pix_fmt yuv420p " + param;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string GetVideoBitrateParam(EncodingJob state, string videoCodec, bool isHls)
|
protected string GetVideoBitrateParam(EncodingJob state, string videoCodec)
|
||||||
{
|
{
|
||||||
var bitrate = state.OutputVideoBitrate;
|
var bitrate = state.OutputVideoBitrate;
|
||||||
|
|
||||||
|
@ -737,14 +736,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// h264
|
// h264
|
||||||
if (isHls)
|
return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
|
||||||
{
|
bitrate.Value.ToString(UsCulture),
|
||||||
return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
|
(bitrate.Value * 2).ToString(UsCulture));
|
||||||
bitrate.Value.ToString(UsCulture),
|
|
||||||
(bitrate.Value * 2).ToString(UsCulture));
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
|
@ -26,7 +26,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
var format = string.Empty;
|
var format = string.Empty;
|
||||||
var keyFrame = string.Empty;
|
var keyFrame = string.Empty;
|
||||||
|
|
||||||
if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
state.Options.Context == EncodingContext.Streaming)
|
||||||
{
|
{
|
||||||
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
|
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
|
||||||
format = " -f mp4 -movflags frag_keyframe+empty_moov";
|
format = " -f mp4 -movflags frag_keyframe+empty_moov";
|
||||||
|
@ -95,7 +96,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
args += GetOutputSizeParam(state, videoCodec);
|
args += GetOutputSizeParam(state, videoCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
var qualityParam = GetVideoQualityParam(state, videoCodec, false);
|
var qualityParam = GetVideoQualityParam(state, videoCodec);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(qualityParam))
|
if (!string.IsNullOrEmpty(qualityParam))
|
||||||
{
|
{
|
||||||
|
|
|
@ -668,6 +668,9 @@
|
||||||
<Compile Include="..\MediaBrowser.Model\FileOrganization\FileSortingStatus.cs">
|
<Compile Include="..\MediaBrowser.Model\FileOrganization\FileSortingStatus.cs">
|
||||||
<Link>FileOrganization\FileSortingStatus.cs</Link>
|
<Link>FileOrganization\FileSortingStatus.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\FileOrganization\SmartMatchInfo.cs">
|
||||||
|
<Link>FileOrganization\SmartMatchInfo.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\MediaBrowser.Model\FileOrganization\TvFileOrganizationOptions.cs">
|
<Compile Include="..\MediaBrowser.Model\FileOrganization\TvFileOrganizationOptions.cs">
|
||||||
<Link>FileOrganization\TvFileOrganizationOptions.cs</Link>
|
<Link>FileOrganization\TvFileOrganizationOptions.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -633,6 +633,9 @@
|
||||||
<Compile Include="..\MediaBrowser.Model\FileOrganization\FileSortingStatus.cs">
|
<Compile Include="..\MediaBrowser.Model\FileOrganization\FileSortingStatus.cs">
|
||||||
<Link>FileOrganization\FileSortingStatus.cs</Link>
|
<Link>FileOrganization\FileSortingStatus.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\FileOrganization\SmartMatchInfo.cs">
|
||||||
|
<Link>FileOrganization\SmartMatchInfo.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\MediaBrowser.Model\FileOrganization\TvFileOrganizationOptions.cs">
|
<Compile Include="..\MediaBrowser.Model\FileOrganization\TvFileOrganizationOptions.cs">
|
||||||
<Link>FileOrganization\TvFileOrganizationOptions.cs</Link>
|
<Link>FileOrganization\TvFileOrganizationOptions.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -9,9 +9,16 @@ namespace MediaBrowser.Model.FileOrganization
|
||||||
/// <value>The tv options.</value>
|
/// <value>The tv options.</value>
|
||||||
public TvFileOrganizationOptions TvOptions { get; set; }
|
public TvFileOrganizationOptions TvOptions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a list of smart match entries.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The smart match entries.</value>
|
||||||
|
public SmartMatchInfo[] SmartMatchInfos { get; set; }
|
||||||
|
|
||||||
public AutoOrganizeOptions()
|
public AutoOrganizeOptions()
|
||||||
{
|
{
|
||||||
TvOptions = new TvFileOrganizationOptions();
|
TvOptions = new TvFileOrganizationOptions();
|
||||||
|
SmartMatchInfos = new SmartMatchInfo[]{};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
MediaBrowser.Model/FileOrganization/SmartMatchInfo.cs
Normal file
16
MediaBrowser.Model/FileOrganization/SmartMatchInfo.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.FileOrganization
|
||||||
|
{
|
||||||
|
public class SmartMatchInfo
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public FileOrganizerType OrganizerType { get; set; }
|
||||||
|
public string[] MatchStrings { get; set; }
|
||||||
|
|
||||||
|
public SmartMatchInfo()
|
||||||
|
{
|
||||||
|
MatchStrings = new string[] { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -137,6 +137,7 @@
|
||||||
<Compile Include="Dto\MetadataEditorInfo.cs" />
|
<Compile Include="Dto\MetadataEditorInfo.cs" />
|
||||||
<Compile Include="Dto\NameIdPair.cs" />
|
<Compile Include="Dto\NameIdPair.cs" />
|
||||||
<Compile Include="Dto\NameValuePair.cs" />
|
<Compile Include="Dto\NameValuePair.cs" />
|
||||||
|
<Compile Include="FileOrganization\SmartMatchInfo.cs" />
|
||||||
<Compile Include="MediaInfo\LiveStreamRequest.cs" />
|
<Compile Include="MediaInfo\LiveStreamRequest.cs" />
|
||||||
<Compile Include="MediaInfo\LiveStreamResponse.cs" />
|
<Compile Include="MediaInfo\LiveStreamResponse.cs" />
|
||||||
<Compile Include="MediaInfo\PlaybackInfoRequest.cs" />
|
<Compile Include="MediaInfo\PlaybackInfoRequest.cs" />
|
||||||
|
|
|
@ -46,12 +46,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
|
|
||||||
public Task<FileOrganizationResult> OrganizeEpisodeFile(string path, CancellationToken cancellationToken)
|
public Task<FileOrganizationResult> OrganizeEpisodeFile(string path, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var options = _config.GetAutoOrganizeOptions().TvOptions;
|
var options = _config.GetAutoOrganizeOptions();
|
||||||
|
|
||||||
return OrganizeEpisodeFile(path, options, false, cancellationToken);
|
return OrganizeEpisodeFile(path, options, false, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FileOrganizationResult> OrganizeEpisodeFile(string path, TvFileOrganizationOptions options, bool overwriteExisting, CancellationToken cancellationToken)
|
public async Task<FileOrganizationResult> OrganizeEpisodeFile(string path, AutoOrganizeOptions options, bool overwriteExisting, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.Info("Sorting file {0}", path);
|
_logger.Info("Sorting file {0}", path);
|
||||||
|
|
||||||
|
@ -110,6 +110,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
premiereDate,
|
premiereDate,
|
||||||
options,
|
options,
|
||||||
overwriteExisting,
|
overwriteExisting,
|
||||||
|
false,
|
||||||
result,
|
result,
|
||||||
cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -145,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FileOrganizationResult> OrganizeWithCorrection(EpisodeFileOrganizationRequest request, TvFileOrganizationOptions options, CancellationToken cancellationToken)
|
public async Task<FileOrganizationResult> OrganizeWithCorrection(EpisodeFileOrganizationRequest request, AutoOrganizeOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var result = _organizationService.GetResult(request.ResultId);
|
var result = _organizationService.GetResult(request.ResultId);
|
||||||
|
|
||||||
|
@ -159,6 +160,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
null,
|
null,
|
||||||
options,
|
options,
|
||||||
true,
|
true,
|
||||||
|
request.RememberCorrection,
|
||||||
result,
|
result,
|
||||||
cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -173,12 +175,13 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
int? episodeNumber,
|
int? episodeNumber,
|
||||||
int? endingEpiosdeNumber,
|
int? endingEpiosdeNumber,
|
||||||
DateTime? premiereDate,
|
DateTime? premiereDate,
|
||||||
TvFileOrganizationOptions options,
|
AutoOrganizeOptions options,
|
||||||
bool overwriteExisting,
|
bool overwriteExisting,
|
||||||
|
bool rememberCorrection,
|
||||||
FileOrganizationResult result,
|
FileOrganizationResult result,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var series = GetMatchingSeries(seriesName, result);
|
var series = GetMatchingSeries(seriesName, result, options);
|
||||||
|
|
||||||
if (series == null)
|
if (series == null)
|
||||||
{
|
{
|
||||||
|
@ -197,6 +200,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
premiereDate,
|
premiereDate,
|
||||||
options,
|
options,
|
||||||
overwriteExisting,
|
overwriteExisting,
|
||||||
|
rememberCorrection,
|
||||||
result,
|
result,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
}
|
}
|
||||||
|
@ -207,15 +211,18 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
int? episodeNumber,
|
int? episodeNumber,
|
||||||
int? endingEpiosdeNumber,
|
int? endingEpiosdeNumber,
|
||||||
DateTime? premiereDate,
|
DateTime? premiereDate,
|
||||||
TvFileOrganizationOptions options,
|
AutoOrganizeOptions options,
|
||||||
bool overwriteExisting,
|
bool overwriteExisting,
|
||||||
|
bool rememberCorrection,
|
||||||
FileOrganizationResult result,
|
FileOrganizationResult result,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path);
|
_logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path);
|
||||||
|
|
||||||
|
var originalExtractedSeriesString = result.ExtractedName;
|
||||||
|
|
||||||
// Proceed to sort the file
|
// Proceed to sort the file
|
||||||
var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options, cancellationToken).ConfigureAwait(false);
|
var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options.TvOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(newPath))
|
if (string.IsNullOrEmpty(newPath))
|
||||||
{
|
{
|
||||||
|
@ -234,7 +241,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
|
|
||||||
if (!overwriteExisting)
|
if (!overwriteExisting)
|
||||||
{
|
{
|
||||||
if (options.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
|
if (options.TvOptions.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
|
||||||
{
|
{
|
||||||
_logger.Info("File {0} already copied to new path {1}, stopping organization", sourcePath, newPath);
|
_logger.Info("File {0} already copied to new path {1}, stopping organization", sourcePath, newPath);
|
||||||
result.Status = FileSortingStatus.SkippedExisting;
|
result.Status = FileSortingStatus.SkippedExisting;
|
||||||
|
@ -251,7 +258,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PerformFileSorting(options, result);
|
PerformFileSorting(options.TvOptions, result);
|
||||||
|
|
||||||
if (overwriteExisting)
|
if (overwriteExisting)
|
||||||
{
|
{
|
||||||
|
@ -285,6 +292,36 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rememberCorrection)
|
||||||
|
{
|
||||||
|
SaveSmartMatchString(originalExtractedSeriesString, series, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveSmartMatchString(string matchString, Series series, AutoOrganizeOptions options)
|
||||||
|
{
|
||||||
|
var seriesIdString = series.Id.ToString("N");
|
||||||
|
SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.Id, seriesIdString));
|
||||||
|
|
||||||
|
if (info == null)
|
||||||
|
{
|
||||||
|
info = new SmartMatchInfo();
|
||||||
|
info.Id = series.Id.ToString("N");
|
||||||
|
info.OrganizerType = FileOrganizerType.Episode;
|
||||||
|
info.Name = series.Name;
|
||||||
|
var list = options.SmartMatchInfos.ToList();
|
||||||
|
list.Add(info);
|
||||||
|
options.SmartMatchInfos = list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.MatchStrings.Contains(matchString, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var list = info.MatchStrings.ToList();
|
||||||
|
list.Add(matchString);
|
||||||
|
info.MatchStrings = list.ToArray();
|
||||||
|
_config.SaveAutoOrganizeOptions(options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteLibraryFile(string path, bool renameRelatedFiles, string targetPath)
|
private void DeleteLibraryFile(string path, bool renameRelatedFiles, string targetPath)
|
||||||
|
@ -435,7 +472,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Series GetMatchingSeries(string seriesName, FileOrganizationResult result)
|
private Series GetMatchingSeries(string seriesName, FileOrganizationResult result, AutoOrganizeOptions options)
|
||||||
{
|
{
|
||||||
var parsedName = _libraryManager.ParseName(seriesName);
|
var parsedName = _libraryManager.ParseName(seriesName);
|
||||||
|
|
||||||
|
@ -445,13 +482,28 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
result.ExtractedName = nameWithoutYear;
|
result.ExtractedName = nameWithoutYear;
|
||||||
result.ExtractedYear = yearInName;
|
result.ExtractedYear = yearInName;
|
||||||
|
|
||||||
return _libraryManager.RootFolder.GetRecursiveChildren(i => i is Series)
|
var series = _libraryManager.RootFolder.GetRecursiveChildren(i => i is Series)
|
||||||
.Cast<Series>()
|
.Cast<Series>()
|
||||||
.Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i))
|
.Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i))
|
||||||
.Where(i => i.Item2 > 0)
|
.Where(i => i.Item2 > 0)
|
||||||
.OrderByDescending(i => i.Item2)
|
.OrderByDescending(i => i.Item2)
|
||||||
.Select(i => i.Item1)
|
.Select(i => i.Item1)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (series == null)
|
||||||
|
{
|
||||||
|
SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(e => e.MatchStrings.Contains(seriesName, StringComparer.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (info != null)
|
||||||
|
{
|
||||||
|
series = _libraryManager.RootFolder
|
||||||
|
.GetRecursiveChildren(i => i is Series)
|
||||||
|
.Cast<Series>()
|
||||||
|
.FirstOrDefault(i => string.Equals(i.Id.ToString("N"), info.Id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return series ?? new Series();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -10,6 +10,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
{
|
{
|
||||||
return manager.GetConfiguration<AutoOrganizeOptions>("autoorganize");
|
return manager.GetConfiguration<AutoOrganizeOptions>("autoorganize");
|
||||||
}
|
}
|
||||||
|
public static void SaveAutoOrganizeOptions(this IConfigurationManager manager, AutoOrganizeOptions options)
|
||||||
|
{
|
||||||
|
manager.SaveConfiguration("autoorganize", options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AutoOrganizeOptionsFactory : IConfigurationFactory
|
public class AutoOrganizeOptionsFactory : IConfigurationFactory
|
||||||
|
|
|
@ -11,6 +11,7 @@ using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommonIO;
|
using CommonIO;
|
||||||
|
@ -96,9 +97,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
return _repo.Delete(resultId);
|
return _repo.Delete(resultId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TvFileOrganizationOptions GetTvOptions()
|
private AutoOrganizeOptions GetAutoOrganizeptions()
|
||||||
{
|
{
|
||||||
return _config.GetAutoOrganizeOptions().TvOptions;
|
return _config.GetAutoOrganizeOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PerformOrganization(string resultId)
|
public async Task PerformOrganization(string resultId)
|
||||||
|
@ -113,7 +114,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
|
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
|
||||||
_libraryMonitor, _providerManager);
|
_libraryMonitor, _providerManager);
|
||||||
|
|
||||||
await organizer.OrganizeEpisodeFile(result.OriginalPath, GetTvOptions(), true, CancellationToken.None)
|
await organizer.OrganizeEpisodeFile(result.OriginalPath, GetAutoOrganizeptions(), true, CancellationToken.None)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +128,60 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
|
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
|
||||||
_libraryMonitor, _providerManager);
|
_libraryMonitor, _providerManager);
|
||||||
|
|
||||||
await organizer.OrganizeWithCorrection(request, GetTvOptions(), CancellationToken.None).ConfigureAwait(false);
|
await organizer.OrganizeWithCorrection(request, GetAutoOrganizeptions(), CancellationToken.None).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryResult<SmartMatchInfo> GetSmartMatchInfos(FileOrganizationResultQuery query)
|
||||||
|
{
|
||||||
|
if (query == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("query");
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = GetAutoOrganizeptions();
|
||||||
|
|
||||||
|
var items = options.SmartMatchInfos.Skip(query.StartIndex ?? 0).Take(query.Limit ?? Int32.MaxValue).ToArray();
|
||||||
|
|
||||||
|
return new QueryResult<SmartMatchInfo>()
|
||||||
|
{
|
||||||
|
Items = items,
|
||||||
|
TotalRecordCount = options.SmartMatchInfos.Length
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteSmartMatchEntry(string IdString, string matchString)
|
||||||
|
{
|
||||||
|
Guid Id;
|
||||||
|
|
||||||
|
if (!Guid.TryParse(IdString, out Id))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(matchString))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("matchString");
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = GetAutoOrganizeptions();
|
||||||
|
|
||||||
|
SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.Id, IdString));
|
||||||
|
|
||||||
|
if (info != null && info.MatchStrings.Contains(matchString))
|
||||||
|
{
|
||||||
|
var list = info.MatchStrings.ToList();
|
||||||
|
list.Remove(matchString);
|
||||||
|
info.MatchStrings = list.ToArray();
|
||||||
|
|
||||||
|
if (info.MatchStrings.Length == 0)
|
||||||
|
{
|
||||||
|
var infos = options.SmartMatchInfos.ToList();
|
||||||
|
infos.Remove(info);
|
||||||
|
options.SmartMatchInfos = infos.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
_config.SaveAutoOrganizeOptions(options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,17 +50,17 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
get { return "Library"; }
|
get { return "Library"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private TvFileOrganizationOptions GetTvOptions()
|
private AutoOrganizeOptions GetAutoOrganizeOptions()
|
||||||
{
|
{
|
||||||
return _config.GetAutoOrganizeOptions().TvOptions;
|
return _config.GetAutoOrganizeOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
||||||
{
|
{
|
||||||
if (GetTvOptions().IsEnabled)
|
if (GetAutoOrganizeOptions().TvOptions.IsEnabled)
|
||||||
{
|
{
|
||||||
await new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _libraryMonitor, _organizationService, _config, _providerManager)
|
await new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _libraryMonitor, _organizationService, _config, _providerManager)
|
||||||
.Organize(GetTvOptions(), cancellationToken, progress).ConfigureAwait(false);
|
.Organize(GetAutoOrganizeOptions(), cancellationToken, progress).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,12 +74,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
|
|
||||||
public bool IsHidden
|
public bool IsHidden
|
||||||
{
|
{
|
||||||
get { return !GetTvOptions().IsEnabled; }
|
get { return !GetAutoOrganizeOptions().TvOptions.IsEnabled; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsEnabled
|
public bool IsEnabled
|
||||||
{
|
{
|
||||||
get { return GetTvOptions().IsEnabled; }
|
get { return GetAutoOrganizeOptions().TvOptions.IsEnabled; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsActivityLogged
|
public bool IsActivityLogged
|
||||||
|
|
|
@ -52,13 +52,13 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Organize(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress<double> progress)
|
public async Task Organize(AutoOrganizeOptions options, CancellationToken cancellationToken, IProgress<double> progress)
|
||||||
{
|
{
|
||||||
var watchLocations = options.WatchLocations.ToList();
|
var watchLocations = options.TvOptions.WatchLocations.ToList();
|
||||||
|
|
||||||
var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
|
var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
|
||||||
.OrderBy(_fileSystem.GetCreationTimeUtc)
|
.OrderBy(_fileSystem.GetCreationTimeUtc)
|
||||||
.Where(i => EnableOrganization(i, options))
|
.Where(i => EnableOrganization(i, options.TvOptions))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var processedFolders = new HashSet<string>();
|
var processedFolders = new HashSet<string>();
|
||||||
|
@ -76,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);
|
var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.TvOptions.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);
|
||||||
if (result.Status == FileSortingStatus.Success && !processedFolders.Contains(file.DirectoryName, StringComparer.OrdinalIgnoreCase))
|
if (result.Status == FileSortingStatus.Success && !processedFolders.Contains(file.DirectoryName, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
processedFolders.Add(file.DirectoryName);
|
processedFolders.Add(file.DirectoryName);
|
||||||
|
@ -100,7 +100,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
|
|
||||||
foreach (var path in processedFolders)
|
foreach (var path in processedFolders)
|
||||||
{
|
{
|
||||||
var deleteExtensions = options.LeftOverFileExtensionsToDelete
|
var deleteExtensions = options.TvOptions.LeftOverFileExtensionsToDelete
|
||||||
.Select(i => i.Trim().TrimStart('.'))
|
.Select(i => i.Trim().TrimStart('.'))
|
||||||
.Where(i => !string.IsNullOrEmpty(i))
|
.Where(i => !string.IsNullOrEmpty(i))
|
||||||
.Select(i => "." + i)
|
.Select(i => "." + i)
|
||||||
|
@ -111,7 +111,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||||
DeleteLeftOverFiles(path, deleteExtensions);
|
DeleteLeftOverFiles(path, deleteExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.DeleteEmptyFolders)
|
if (options.TvOptions.DeleteEmptyFolders)
|
||||||
{
|
{
|
||||||
if (!IsWatchFolder(path, watchLocations))
|
if (!IsWatchFolder(path, watchLocations))
|
||||||
{
|
{
|
||||||
|
|
|
@ -165,11 +165,14 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||||
|
|
||||||
var item = _libraryManager.GetItemById(id);
|
var item = _libraryManager.GetItemById(id);
|
||||||
|
|
||||||
await _libraryManager.DeleteItem(item, new DeleteOptions
|
if (item != null)
|
||||||
{
|
{
|
||||||
DeleteFileLocation = false
|
await _libraryManager.DeleteItem(item, new DeleteOptions
|
||||||
|
{
|
||||||
|
DeleteFileLocation = false
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.Report(100);
|
progress.Report(100);
|
||||||
|
|
|
@ -171,7 +171,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
epgData = GetEpgDataForChannel(timer.ChannelId);
|
epgData = GetEpgDataForChannel(timer.ChannelId);
|
||||||
}
|
}
|
||||||
await UpdateTimersForSeriesTimer(epgData, timer, false).ConfigureAwait(false);
|
await UpdateTimersForSeriesTimer(epgData, timer, true).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var timers = await GetTimersAsync(cancellationToken).ConfigureAwait(false);
|
var timers = await GetTimersAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
@ -664,12 +664,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
throw new ArgumentNullException("timer");
|
throw new ArgumentNullException("timer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProgramInfo info = null;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(timer.ProgramId))
|
if (string.IsNullOrWhiteSpace(timer.ProgramId))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("timer.ProgramId is null. Cannot record.");
|
_logger.Info("Timer {0} has null programId", timer.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId);
|
if (info == null)
|
||||||
|
{
|
||||||
|
_logger.Info("Unable to find program with Id {0}. Will search using start date", timer.ProgramId);
|
||||||
|
info = GetProgramInfoFromCache(timer.ChannelId, timer.StartDate);
|
||||||
|
}
|
||||||
|
|
||||||
if (info == null)
|
if (info == null)
|
||||||
{
|
{
|
||||||
|
@ -775,14 +785,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false))
|
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
_logger.Info("Opened recording stream from tuner provider");
|
_logger.Info("Opened recording stream from tuner provider");
|
||||||
|
|
||||||
using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||||
{
|
{
|
||||||
result.Item2.Release();
|
result.Item2.Release();
|
||||||
isResourceOpen = false;
|
isResourceOpen = false;
|
||||||
|
|
||||||
_logger.Info("Copying recording stream to file stream");
|
_logger.Info("Copying recording stream to file stream");
|
||||||
|
|
||||||
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken).ConfigureAwait(false);
|
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -867,6 +877,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
return epgData.FirstOrDefault(p => string.Equals(p.Id, programId, StringComparison.OrdinalIgnoreCase));
|
return epgData.FirstOrDefault(p => string.Equals(p.Id, programId, StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ProgramInfo GetProgramInfoFromCache(string channelId, DateTime startDateUtc)
|
||||||
|
{
|
||||||
|
var epgData = GetEpgDataForChannel(channelId);
|
||||||
|
var startDateTicks = startDateUtc.Ticks;
|
||||||
|
// Find the first program that starts within 3 minutes
|
||||||
|
return epgData.FirstOrDefault(p => Math.Abs(startDateTicks - p.StartDate.Ticks) <= TimeSpan.FromMinutes(3).Ticks);
|
||||||
|
}
|
||||||
|
|
||||||
private string RecordingPath
|
private string RecordingPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -46,55 +46,61 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
||||||
|
|
||||||
protected override async Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
|
protected override async Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var url = info.Url;
|
var urlHash = info.Url.GetMD5().ToString("N");
|
||||||
var urlHash = url.GetMD5().ToString("N");
|
|
||||||
|
|
||||||
string line;
|
|
||||||
// Read the file and display it line by line.
|
// Read the file and display it line by line.
|
||||||
using (var file = new StreamReader(await GetListingsStream(info, cancellationToken).ConfigureAwait(false)))
|
using (var reader = new StreamReader(await GetListingsStream(info, cancellationToken).ConfigureAwait(false)))
|
||||||
{
|
{
|
||||||
var channels = new List<M3UChannel>();
|
return GetChannels(reader, urlHash);
|
||||||
|
|
||||||
string channnelName = null;
|
|
||||||
string channelNumber = null;
|
|
||||||
|
|
||||||
while ((line = file.ReadLine()) != null)
|
|
||||||
{
|
|
||||||
line = line.Trim();
|
|
||||||
if (string.IsNullOrWhiteSpace(line))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.StartsWith("#EXTINF:", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var parts = line.Split(new[] { ':' }, 2).Last().Split(new[] { ',' }, 2);
|
|
||||||
channelNumber = parts[0];
|
|
||||||
channnelName = parts[1];
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrWhiteSpace(channelNumber))
|
|
||||||
{
|
|
||||||
channels.Add(new M3UChannel
|
|
||||||
{
|
|
||||||
Name = channnelName,
|
|
||||||
Number = channelNumber,
|
|
||||||
Id = ChannelIdPrefix + urlHash + channelNumber,
|
|
||||||
Path = line
|
|
||||||
});
|
|
||||||
|
|
||||||
channelNumber = null;
|
|
||||||
channnelName = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return channels;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<M3UChannel> GetChannels(StreamReader reader, string urlHash)
|
||||||
|
{
|
||||||
|
var channels = new List<M3UChannel>();
|
||||||
|
|
||||||
|
string channnelName = null;
|
||||||
|
string channelNumber = null;
|
||||||
|
string line;
|
||||||
|
|
||||||
|
while ((line = reader.ReadLine()) != null)
|
||||||
|
{
|
||||||
|
line = line.Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.StartsWith("#EXTINF:", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
line = line.Substring(8);
|
||||||
|
Logger.Info("Found m3u channel: {0}", line);
|
||||||
|
var parts = line.Split(new[] { ',' }, 2);
|
||||||
|
channelNumber = parts[0];
|
||||||
|
channnelName = parts[1];
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrWhiteSpace(channelNumber))
|
||||||
|
{
|
||||||
|
channels.Add(new M3UChannel
|
||||||
|
{
|
||||||
|
Name = channnelName,
|
||||||
|
Number = channelNumber,
|
||||||
|
Id = ChannelIdPrefix + urlHash + line.GetMD5().ToString("N"),
|
||||||
|
Path = line
|
||||||
|
});
|
||||||
|
|
||||||
|
channelNumber = null;
|
||||||
|
channnelName = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
|
||||||
public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
|
public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var list = GetConfiguration().TunerHosts
|
var list = GetConfiguration().TunerHosts
|
||||||
|
@ -159,8 +165,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//channelId = channelId.Substring(prefix.Length);
|
|
||||||
|
|
||||||
var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false);
|
var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false);
|
||||||
var m3uchannels = channels.Cast<M3UChannel>();
|
var m3uchannels = channels.Cast<M3UChannel>();
|
||||||
var channel = m3uchannels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase));
|
var channel = m3uchannels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
|
@ -45,6 +45,9 @@
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll</HintPath>
|
<HintPath>..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Emby.XmlTv">
|
||||||
|
<HintPath>..\packages\Emby.XmlTv.1.0.0.46\lib\net45\Emby.XmlTv.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Interfaces.IO">
|
<Reference Include="Interfaces.IO">
|
||||||
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
|
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
/// <value>The name.</value>
|
/// <value>The name.</value>
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return ItemSortBy.Album; }
|
get { return ItemSortBy.IsFolder; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="CommonIO" version="1.0.0.7" targetFramework="net45" />
|
<package id="CommonIO" version="1.0.0.7" targetFramework="net45" />
|
||||||
|
<package id="Emby.XmlTv" version="1.0.0.46" targetFramework="net45" />
|
||||||
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
|
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
|
||||||
<package id="MediaBrowser.Naming" version="1.0.0.46" targetFramework="net45" />
|
<package id="MediaBrowser.Naming" version="1.0.0.46" targetFramework="net45" />
|
||||||
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
|
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
|
||||||
|
|
|
@ -477,7 +477,6 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
var files = new[]
|
var files = new[]
|
||||||
{
|
{
|
||||||
"thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.theme.css",
|
|
||||||
"css/site.css",
|
"css/site.css",
|
||||||
"css/librarymenu.css",
|
"css/librarymenu.css",
|
||||||
"css/librarybrowser.css",
|
"css/librarybrowser.css",
|
||||||
|
|
|
@ -101,6 +101,12 @@
|
||||||
<Content Include="dashboard-ui\components\chromecasthelpers.js">
|
<Content Include="dashboard-ui\components\chromecasthelpers.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\autoorganizesmart.html">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\bower_components\fastclick\lib\fastclick.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\components\recordingcreator\recordingcreator.js">
|
<Content Include="dashboard-ui\components\recordingcreator\recordingcreator.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -281,6 +287,9 @@
|
||||||
<Content Include="dashboard-ui\scripts\mysyncsettings.js">
|
<Content Include="dashboard-ui\scripts\mysyncsettings.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\scripts\autoorganizesmart.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\scripts\searchmenu.js">
|
<Content Include="dashboard-ui\scripts\searchmenu.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -368,15 +377,9 @@
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.controlgroup.css">
|
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.controlgroup.css">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.controlgroup.js">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.listview.css">
|
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.listview.css">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.listview.js">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.panel.css">
|
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.panel.css">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -1039,309 +1042,6 @@
|
||||||
<Content Include="dashboard-ui\scripts\wizardsettings.js">
|
<Content Include="dashboard-ui\scripts\wizardsettings.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\ajax-loader.gif">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\action-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\action-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\alert-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\alert-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-d-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-d-l-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-d-l-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-d-r-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-d-r-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-d-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-l-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-l-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-r-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-r-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-u-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-u-l-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-u-l-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-u-r-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-u-r-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\arrow-u-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\audio-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\audio-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\back-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\back-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\bars-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\bars-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\bullets-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\bullets-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\calendar-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\calendar-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\camera-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\camera-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\carat-d-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\carat-d-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\carat-l-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\carat-l-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\carat-r-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\carat-r-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\carat-u-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\carat-u-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\check-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\check-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\clock-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\clock-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\cloud-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\cloud-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\comment-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\comment-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\delete-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\delete-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\edit-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\edit-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\eye-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\eye-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\forbidden-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\forbidden-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\forward-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\forward-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\gear-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\gear-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\grid-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\grid-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\heart-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\heart-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\home-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\home-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\info-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\info-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\location-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\location-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\lock-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\lock-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\mail-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\mail-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\minus-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\minus-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\navigation-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\navigation-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\phone-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\phone-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\plus-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\plus-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\power-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\power-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\recycle-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\recycle-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\refresh-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\refresh-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\search-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\search-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\shop-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\shop-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\star-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\star-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\tag-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\tag-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\user-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\user-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\video-black.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-png\video-white.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-svg\action-black.svg">
|
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-svg\action-black.svg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user