|
@@ -39,68 +39,45 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
|
|
var url = info.Url;
|
|
|
var urlHash = url.GetMD5().ToString("N");
|
|
|
|
|
|
- int position = 0;
|
|
|
string line;
|
|
|
// Read the file and display it line by line.
|
|
|
var file = new StreamReader(url);
|
|
|
var channels = new List<M3UChannel>();
|
|
|
+
|
|
|
+ string channnelName = null;
|
|
|
+ string channelNumber = null;
|
|
|
+
|
|
|
while ((line = file.ReadLine()) != null)
|
|
|
{
|
|
|
line = line.Trim();
|
|
|
- if (!String.IsNullOrWhiteSpace(line))
|
|
|
+ if (string.IsNullOrWhiteSpace(line))
|
|
|
{
|
|
|
- if (position == 0 && !line.StartsWith("#EXTM3U"))
|
|
|
- {
|
|
|
- throw new ApplicationException("wrong file");
|
|
|
- }
|
|
|
- if (position % 2 == 0)
|
|
|
- {
|
|
|
- if (position != 0)
|
|
|
- {
|
|
|
- channels.Last().Path = line;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- line = line.Replace("#EXTM3U", "");
|
|
|
- line = line.Trim();
|
|
|
- var vars = line.Split(' ').ToList();
|
|
|
- foreach (var variable in vars)
|
|
|
- {
|
|
|
- var list = variable.Replace('"', ' ').Split('=');
|
|
|
- switch (list[0])
|
|
|
- {
|
|
|
- case ("id"):
|
|
|
- //_id = list[1];
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
+ 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
|
|
|
{
|
|
|
- if (!line.StartsWith("#EXTINF:")) { throw new ApplicationException("Bad file"); }
|
|
|
- line = line.Replace("#EXTINF:", "");
|
|
|
- var nameStart = line.LastIndexOf(',');
|
|
|
- line = line.Substring(0, nameStart);
|
|
|
- var vars = line.Split(' ').ToList();
|
|
|
- vars.RemoveAt(0);
|
|
|
- channels.Add(new M3UChannel());
|
|
|
- foreach (var variable in vars)
|
|
|
- {
|
|
|
- var list = variable.Replace('"', ' ').Split('=');
|
|
|
- switch (list[0])
|
|
|
- {
|
|
|
- case "tvg-id":
|
|
|
- channels.Last().Id = ChannelIdPrefix + urlHash + list[1];
|
|
|
- channels.Last().Number = list[1];
|
|
|
- break;
|
|
|
- case "tvg-name":
|
|
|
- channels.Last().Name = list[1];
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- position++;
|
|
|
+ Name = channnelName,
|
|
|
+ Number = channelNumber,
|
|
|
+ Id = ChannelIdPrefix + urlHash + channelNumber,
|
|
|
+ Path = line
|
|
|
+ });
|
|
|
+
|
|
|
+ channelNumber = null;
|
|
|
+ channnelName = null;
|
|
|
}
|
|
|
}
|
|
|
file.Close();
|
|
@@ -125,6 +102,35 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
|
|
}
|
|
|
|
|
|
protected override async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false);
|
|
|
+
|
|
|
+ return sources.First();
|
|
|
+ }
|
|
|
+
|
|
|
+ class M3UChannel : ChannelInfo
|
|
|
+ {
|
|
|
+ public string Path { get; set; }
|
|
|
+
|
|
|
+ public M3UChannel()
|
|
|
+ {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task Validate(TunerHostInfo info)
|
|
|
+ {
|
|
|
+ if (!File.Exists(info.Url))
|
|
|
+ {
|
|
|
+ throw new FileNotFoundException();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override bool IsValidChannelId(string channelId)
|
|
|
+ {
|
|
|
+ return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
|
|
|
{
|
|
|
var urlHash = info.Url.GetMD5().ToString("N");
|
|
|
var prefix = ChannelIdPrefix + urlHash;
|
|
@@ -133,29 +139,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- channelId = channelId.Substring(prefix.Length);
|
|
|
+ //channelId = channelId.Substring(prefix.Length);
|
|
|
|
|
|
var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false);
|
|
|
var m3uchannels = channels.Cast<M3UChannel>();
|
|
|
- var channel = m3uchannels.FirstOrDefault(c => c.Id == channelId);
|
|
|
+ var channel = m3uchannels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase));
|
|
|
if (channel != null)
|
|
|
{
|
|
|
var path = channel.Path;
|
|
|
MediaProtocol protocol = MediaProtocol.File;
|
|
|
- if (path.StartsWith("http"))
|
|
|
+ if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
protocol = MediaProtocol.Http;
|
|
|
}
|
|
|
- else if (path.StartsWith("rtmp"))
|
|
|
+ else if (path.StartsWith("rtmp", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
protocol = MediaProtocol.Rtmp;
|
|
|
}
|
|
|
- else if (path.StartsWith("rtsp"))
|
|
|
+ else if (path.StartsWith("rtsp", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
protocol = MediaProtocol.Rtsp;
|
|
|
}
|
|
|
|
|
|
- return new MediaSourceInfo
|
|
|
+ var mediaSource = new MediaSourceInfo
|
|
|
{
|
|
|
Path = channel.Path,
|
|
|
Protocol = protocol,
|
|
@@ -179,35 +185,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
|
|
RequiresOpening = false,
|
|
|
RequiresClosing = false
|
|
|
};
|
|
|
- }
|
|
|
- throw new ApplicationException("Host doesnt provide this channel");
|
|
|
- }
|
|
|
-
|
|
|
- class M3UChannel : ChannelInfo
|
|
|
- {
|
|
|
- public string Path { get; set; }
|
|
|
-
|
|
|
- public M3UChannel()
|
|
|
- {
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- public async Task Validate(TunerHostInfo info)
|
|
|
- {
|
|
|
- if (!File.Exists(info.Url))
|
|
|
- {
|
|
|
- throw new FileNotFoundException();
|
|
|
+ return new List<MediaSourceInfo> { mediaSource };
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- protected override bool IsValidChannelId(string channelId)
|
|
|
- {
|
|
|
- return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
|
|
|
- }
|
|
|
-
|
|
|
- protected override Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
|
|
|
- {
|
|
|
- throw new NotImplementedException();
|
|
|
+ return new List<MediaSourceInfo> { };
|
|
|
}
|
|
|
|
|
|
protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
|