├── .gitignore ├── LICENSE.md ├── MediaBrowser.Channels.IPTV.sln ├── MediaBrowser.Channels.IPTV ├── Api │ └── ServerApiEndpoints.cs ├── Channel.cs ├── ChannelMediaInfo.cs ├── Configuration │ ├── PluginConfiguration.cs │ └── configPage.html ├── MediaBrowser.Channels.IPTV.csproj └── Plugin.cs ├── README.md └── build.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | ################# 32 | ## Media Browser 33 | ################# 34 | ProgramData*/ 35 | ProgramData-Server*/ 36 | ProgramData-UI*/ 37 | 38 | ################# 39 | ## Visual Studio 40 | ################# 41 | 42 | .vs 43 | 44 | ## Ignore Visual Studio temporary files, build results, and 45 | ## files generated by popular Visual Studio add-ons. 46 | 47 | # User-specific files 48 | *.suo 49 | *.user 50 | *.sln.docstates 51 | 52 | # Build results 53 | 54 | [Dd]ebug/ 55 | [Rr]elease/ 56 | build/ 57 | [Bb]in/ 58 | [Oo]bj/ 59 | 60 | # MSTest test Results 61 | [Tt]est[Rr]esult*/ 62 | [Bb]uild[Ll]og.* 63 | 64 | *_i.c 65 | *_p.c 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.pch 70 | *.pdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.log 86 | *.scc 87 | *.scc 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.orig 92 | *.rej 93 | *.sdf 94 | *.opensdf 95 | *.ipch 96 | 97 | # Visual C++ cache files 98 | ipch/ 99 | *.aps 100 | *.ncb 101 | *.opensdf 102 | *.sdf 103 | *.cachefile 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | 110 | # Guidance Automation Toolkit 111 | *.gpState 112 | 113 | # ReSharper is a .NET coding add-in 114 | _ReSharper*/ 115 | *.[Rr]e[Ss]harper 116 | 117 | # TeamCity is a build add-in 118 | _TeamCity* 119 | 120 | # DotCover is a Code Coverage Tool 121 | *.dotCover 122 | 123 | # NCrunch 124 | *.ncrunch* 125 | .*crunch*.local.xml 126 | 127 | # Installshield output folder 128 | [Ee]xpress/ 129 | 130 | # DocProject is a documentation generator add-in 131 | DocProject/buildhelp/ 132 | DocProject/Help/*.HxT 133 | DocProject/Help/*.HxC 134 | DocProject/Help/*.hhc 135 | DocProject/Help/*.hhk 136 | DocProject/Help/*.hhp 137 | DocProject/Help/Html2 138 | DocProject/Help/html 139 | 140 | # Click-Once directory 141 | publish/ 142 | 143 | # Publish Web Output 144 | *.Publish.xml 145 | *.pubxml 146 | 147 | # NuGet Packages Directory 148 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 149 | packages/ 150 | 151 | # Windows Azure Build Output 152 | csx 153 | *.build.csdef 154 | 155 | # Windows Store app package directory 156 | AppPackages/ 157 | 158 | # Others 159 | sql/ 160 | *.Cache 161 | ClientBin/ 162 | [Ss]tyle[Cc]op.* 163 | ~$* 164 | *~ 165 | *.dbmdl 166 | *.[Pp]ublish.xml 167 | *.publishsettings 168 | 169 | # RIA/Silverlight projects 170 | Generated_Code/ 171 | 172 | # Backup & report files from converting an old project file to a newer 173 | # Visual Studio version. Backup files are not needed, because we have git ;-) 174 | _UpgradeReport_Files/ 175 | Backup*/ 176 | UpgradeLog*.XML 177 | UpgradeLog*.htm 178 | 179 | # SQL Server files 180 | App_Data/*.mdf 181 | App_Data/*.ldf 182 | 183 | ############# 184 | ## Windows detritus 185 | ############# 186 | 187 | # Windows image file caches 188 | Thumbs.db 189 | ehthumbs.db 190 | 191 | # Folder config file 192 | Desktop.ini 193 | 194 | # Recycle Bin used on file shares 195 | $RECYCLE.BIN/ 196 | 197 | # Mac crap 198 | .DS_Store 199 | 200 | 201 | ############# 202 | ## Python 203 | ############# 204 | 205 | *.py[co] 206 | 207 | # Packages 208 | *.egg 209 | *.egg-info 210 | dist/ 211 | build/ 212 | eggs/ 213 | parts/ 214 | var/ 215 | sdist/ 216 | develop-eggs/ 217 | .installed.cfg 218 | 219 | # Installer logs 220 | pip-log.txt 221 | 222 | # Unit test / coverage reports 223 | .coverage 224 | .tox 225 | 226 | #Translations 227 | *.mo 228 | 229 | #Mr Developer 230 | .mr.developer.cfg 231 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) Media Browser http://mediabrowser.tv 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /MediaBrowser.Channels.IPTV.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Channels.IPTV", "MediaBrowser.Channels.IPTV\MediaBrowser.Channels.IPTV.csproj", "{DF0302B3-DF91-409D-9696-F027E2D16863}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {DF0302B3-DF91-409D-9696-F027E2D16863}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {DF0302B3-DF91-409D-9696-F027E2D16863}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {DF0302B3-DF91-409D-9696-F027E2D16863}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {DF0302B3-DF91-409D-9696-F027E2D16863}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {A826C9EE-5710-4047-8A2C-F03B2AC857F7} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /MediaBrowser.Channels.IPTV/Api/ServerApiEndpoints.cs: -------------------------------------------------------------------------------- 1 | using MediaBrowser.Channels.IPTV.Configuration; 2 | using MediaBrowser.Controller.Net; 3 | using MediaBrowser.Model.MediaInfo; 4 | using System; 5 | using System.Linq; 6 | using MediaBrowser.Model.Services; 7 | 8 | namespace MediaBrowser.Channels.IPTV.Api 9 | { 10 | [Route("/Iptv/Bookmarks", "POST", Summary = "Bookmarks a video")] 11 | public class VideoSend : IReturnVoid 12 | { 13 | [ApiMember(Name = "Name", Description = "Name", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "POST")] 14 | public string Name { get; set; } 15 | 16 | [ApiMember(Name = "Path", Description = "Path", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] 17 | public string Path { get; set; } 18 | 19 | [ApiMember(Name = "UserId", Description = "UserId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] 20 | public string UserId { get; set; } 21 | 22 | [ApiMember(Name = "Protocol", Description = "Protocol", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] 23 | public MediaProtocol Protocol { get; set; } 24 | 25 | [ApiMember(Name = "ImagePath", Description = "ImagePath", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "POST")] 26 | public string ImagePath { get; set; } 27 | } 28 | 29 | public class ServerApiEndpoints : IService 30 | { 31 | public void Post(VideoSend request) 32 | { 33 | if (string.IsNullOrWhiteSpace(request.Name)) 34 | { 35 | throw new ArgumentException("Name cannot be empty."); 36 | } 37 | 38 | if (string.IsNullOrWhiteSpace(request.Path)) 39 | { 40 | throw new ArgumentException("Path cannot be empty."); 41 | } 42 | 43 | if (string.IsNullOrWhiteSpace(request.UserId)) 44 | { 45 | throw new ArgumentException("UserId cannot be empty."); 46 | } 47 | 48 | var list = Plugin.Instance.Configuration.Bookmarks.ToList(); 49 | list.Add(new Bookmark 50 | { 51 | UserId = request.UserId, 52 | Name = request.Name, 53 | Image = request.ImagePath, 54 | Path = request.Path, 55 | Protocol = request.Protocol 56 | }); 57 | 58 | Plugin.Instance.Configuration.Bookmarks = list.ToArray(); 59 | 60 | Plugin.Instance.SaveConfiguration(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MediaBrowser.Channels.IPTV/Channel.cs: -------------------------------------------------------------------------------- 1 | using MediaBrowser.Controller.Channels; 2 | using MediaBrowser.Controller.Drawing; 3 | using MediaBrowser.Controller.Providers; 4 | using MediaBrowser.Model.Channels; 5 | using MediaBrowser.Model.Drawing; 6 | using MediaBrowser.Model.Entities; 7 | using Microsoft.Extensions.Logging; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using MediaBrowser.Model.Dto; 14 | 15 | namespace MediaBrowser.Channels.IPTV 16 | { 17 | public class Channel : IChannel, IHasCacheKey 18 | { 19 | private readonly ILogger _logger; 20 | 21 | public Channel(ILogger logger) 22 | { 23 | _logger = logger; 24 | } 25 | 26 | // Increment as needed to invalidate all caches 27 | public string DataVersion => "1"; 28 | 29 | public Task GetChannelItems(InternalChannelItemQuery query, CancellationToken cancellationToken) 30 | { 31 | _logger.LogDebug("cat ID : {Id}", query.FolderId); 32 | 33 | return GetChannelItemsInternal(cancellationToken); 34 | } 35 | 36 | 37 | private Task GetChannelItemsInternal(CancellationToken cancellationToken) 38 | { 39 | var items = new List(); 40 | 41 | foreach (var s in Plugin.Instance.Configuration.Bookmarks) 42 | { 43 | // Until we have user configuration in the UI, we have to disable this. 44 | //if (!string.Equals(s.UserId, userId, StringComparison.OrdinalIgnoreCase)) 45 | //{ 46 | // continue; 47 | //} 48 | 49 | var item = new ChannelItemInfo 50 | { 51 | Name = s.Name, 52 | ImageUrl = s.Image, 53 | Id = s.Name, 54 | Type = ChannelItemType.Media, 55 | ContentType = ChannelMediaContentType.Clip, 56 | MediaType = ChannelMediaType.Video, 57 | 58 | MediaSources = new List 59 | { 60 | new ChannelMediaInfo 61 | { 62 | Path = s.Path, 63 | Protocol = s.Protocol 64 | 65 | }.ToMediaSource() 66 | } 67 | }; 68 | 69 | items.Add(item); 70 | } 71 | 72 | return Task.FromResult(new ChannelItemResult 73 | { 74 | Items = items 75 | }); 76 | } 77 | 78 | public IEnumerable GetSupportedChannelImages() 79 | { 80 | return new List 81 | { 82 | ImageType.Thumb, 83 | ImageType.Backdrop 84 | }; 85 | } 86 | 87 | public string HomePageUrl => string.Empty; 88 | 89 | public string Name => "IPTV"; 90 | 91 | public InternalChannelFeatures GetChannelFeatures() 92 | { 93 | return new InternalChannelFeatures 94 | { 95 | ContentTypes = new List 96 | { 97 | ChannelMediaContentType.Clip 98 | }, 99 | 100 | MediaTypes = new List 101 | { 102 | ChannelMediaType.Video 103 | }, 104 | 105 | SupportsContentDownloading = true 106 | }; 107 | } 108 | 109 | public Task GetChannelImage(ImageType type, CancellationToken cancellationToken) 110 | { 111 | switch (type) 112 | { 113 | case ImageType.Thumb: 114 | case ImageType.Backdrop: 115 | { 116 | var path = GetType().Namespace + ".Images." + type.ToString().ToLowerInvariant() + ".png"; 117 | 118 | return Task.FromResult(new DynamicImageResponse 119 | { 120 | Format = ImageFormat.Png, 121 | HasImage = true, 122 | Stream = typeof(Channel).Assembly.GetManifestResourceStream(path) 123 | }); 124 | } 125 | default: 126 | throw new ArgumentException("Unsupported image type: " + type); 127 | } 128 | } 129 | 130 | public bool IsEnabledFor(string userId) 131 | { 132 | return true; 133 | } 134 | 135 | public ChannelParentalRating ParentalRating 136 | => ChannelParentalRating.GeneralAudience; 137 | 138 | public string GetCacheKey(string userId) 139 | => Guid.NewGuid().ToString("N"); 140 | 141 | public string Description => string.Empty; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /MediaBrowser.Channels.IPTV/ChannelMediaInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using MediaBrowser.Model.Dto; 5 | using MediaBrowser.Model.MediaInfo; 6 | using MediaBrowser.Model.Entities; 7 | using MediaBrowser.Common.Extensions; 8 | using System.Linq; 9 | 10 | namespace MediaBrowser.Channels.IPTV 11 | { 12 | public class ChannelMediaInfo 13 | { 14 | public string Path { get; set; } 15 | 16 | public Dictionary RequiredHttpHeaders { get; set; } 17 | 18 | public string Container { get; set; } 19 | public string AudioCodec { get; set; } 20 | public string VideoCodec { get; set; } 21 | 22 | public int? AudioBitrate { get; set; } 23 | public int? VideoBitrate { get; set; } 24 | public int? Width { get; set; } 25 | public int? Height { get; set; } 26 | public int? AudioChannels { get; set; } 27 | public int? AudioSampleRate { get; set; } 28 | 29 | public string VideoProfile { get; set; } 30 | public float? VideoLevel { get; set; } 31 | public float? Framerate { get; set; } 32 | 33 | public bool? IsAnamorphic { get; set; } 34 | 35 | public MediaProtocol Protocol { get; set; } 36 | 37 | public long? RunTimeTicks { get; set; } 38 | 39 | public string Id { get; set; } 40 | 41 | public bool ReadAtNativeFramerate { get; set; } 42 | public bool SupportsDirectPlay { get; set; } 43 | 44 | public ChannelMediaInfo() 45 | { 46 | RequiredHttpHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); 47 | 48 | // This is most common 49 | Protocol = MediaProtocol.Http; 50 | SupportsDirectPlay = true; 51 | } 52 | 53 | public MediaSourceInfo ToMediaSource() 54 | { 55 | var id = Path.GetMD5().ToString("N"); 56 | 57 | var source = new MediaSourceInfo 58 | { 59 | MediaStreams = GetMediaStreams(this).ToList(), 60 | 61 | Container = Container, 62 | Protocol = Protocol, 63 | Path = Path, 64 | RequiredHttpHeaders = RequiredHttpHeaders, 65 | RunTimeTicks = RunTimeTicks, 66 | Name = id, 67 | Id = id, 68 | ReadAtNativeFramerate = ReadAtNativeFramerate, 69 | SupportsDirectStream = Protocol == MediaProtocol.Http && !string.IsNullOrWhiteSpace(Container) && !string.Equals(Container, "hls", StringComparison.OrdinalIgnoreCase), 70 | SupportsDirectPlay = SupportsDirectPlay, 71 | IsRemote = true 72 | }; 73 | 74 | source.InferTotalBitrate(); 75 | 76 | return source; 77 | } 78 | 79 | private IEnumerable GetMediaStreams(ChannelMediaInfo info) 80 | { 81 | if (!string.IsNullOrWhiteSpace(info.VideoCodec)) 82 | { 83 | yield return new MediaStream 84 | { 85 | Type = MediaStreamType.Video, 86 | Width = info.Width, 87 | RealFrameRate = info.Framerate, 88 | Profile = info.VideoProfile, 89 | Level = info.VideoLevel, 90 | Index = -1, 91 | Height = info.Height, 92 | Codec = info.VideoCodec, 93 | BitRate = info.VideoBitrate, 94 | AverageFrameRate = info.Framerate 95 | }; 96 | } 97 | 98 | if (!string.IsNullOrWhiteSpace(info.AudioCodec)) 99 | { 100 | yield return new MediaStream 101 | { 102 | Type = MediaStreamType.Audio, 103 | Index = -1, 104 | Codec = info.AudioCodec, 105 | BitRate = info.AudioBitrate, 106 | Channels = info.AudioChannels, 107 | SampleRate = info.AudioSampleRate 108 | }; 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /MediaBrowser.Channels.IPTV/Configuration/PluginConfiguration.cs: -------------------------------------------------------------------------------- 1 | using MediaBrowser.Model.MediaInfo; 2 | using MediaBrowser.Model.Plugins; 3 | using System; 4 | 5 | namespace MediaBrowser.Channels.IPTV.Configuration 6 | { 7 | /// 8 | /// Class PluginConfiguration 9 | /// 10 | public class PluginConfiguration : BasePluginConfiguration 11 | { 12 | 13 | /// 14 | /// List of feeds 15 | /// 16 | /// urls of xml podcast feeds 17 | public Bookmark[] Bookmarks { get; set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | public PluginConfiguration() 23 | { 24 | Bookmarks = Array.Empty(); 25 | } 26 | } 27 | 28 | public class Bookmark 29 | { 30 | public String Name { get; set; } 31 | public String Image { get; set; } 32 | public String Path { get; set; } 33 | public MediaProtocol Protocol { get; set; } 34 | public String UserId { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /MediaBrowser.Channels.IPTV/Configuration/configPage.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | IPTV 5 | 6 | 7 |
8 |
9 |
10 |
11 |
12 |

IPTV Streams

13 | 17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |

New IPTV Stream

26 |
27 |
28 |
29 | 30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 | 44 |
45 |

46 | 49 | 52 |

53 |
54 |
55 |
56 |
57 | 172 |
173 | 174 | 175 | -------------------------------------------------------------------------------- /MediaBrowser.Channels.IPTV/MediaBrowser.Channels.IPTV.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | 6.0.0.0 6 | 6.0.0.0 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /MediaBrowser.Channels.IPTV/Plugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using MediaBrowser.Channels.IPTV.Configuration; 5 | using MediaBrowser.Common.Configuration; 6 | using MediaBrowser.Common.Plugins; 7 | using MediaBrowser.Model.Plugins; 8 | using MediaBrowser.Model.Serialization; 9 | using MediaBrowser.Model.Drawing; 10 | using Microsoft.Extensions.Logging; 11 | 12 | namespace MediaBrowser.Channels.IPTV 13 | { 14 | /// 15 | /// Class Plugin 16 | /// 17 | public class Plugin : BasePlugin, IHasWebPages 18 | { 19 | private readonly Guid _id = new Guid("a59b5c4b-05a8-488f-bfa8-7a63fffc7639"); 20 | 21 | public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) 22 | : base(applicationPaths, xmlSerializer) 23 | { 24 | Instance = this; 25 | } 26 | 27 | public override Guid Id => _id; 28 | 29 | /// 30 | /// Gets the name of the plugin 31 | /// 32 | /// The name. 33 | public override string Name => "IPTV"; 34 | 35 | /// 36 | /// Gets the description. 37 | /// 38 | /// The description. 39 | public override string Description 40 | => "Bookmark your favorite internet videos"; 41 | 42 | /// 43 | /// Gets the instance. 44 | /// 45 | /// The instance. 46 | public static Plugin Instance { get; private set; } 47 | 48 | public IEnumerable GetPages() 49 | { 50 | return new[] 51 | { 52 | new PluginPageInfo 53 | { 54 | Name = "iptv", 55 | EmbeddedResourcePath = GetType().Namespace + ".Configuration.configPage.html" 56 | } 57 | }; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jellyfin-plugin-iptv 2 | -------------------------------------------------------------------------------- /build.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "IPTV" 3 | guid: "a59b5c4b-05a8-488f-bfa8-7a63fffc7639" 4 | version: "6.0.0.0" 5 | targetAbi: "10.6.0.0" 6 | owner: "jellyfin" 7 | overview: "Enable IPTV support in Jellyfin" 8 | description: "Enable IPTV support in Jellyfin" 9 | category: "Channel" 10 | artifacts: 11 | - "MediaBrowser.Channels.IPTV.dll" 12 | changelog: > 13 | changelog 14 | --------------------------------------------------------------------------------