Bladeren bron

update tuner setup

Luke Pulverenti 10 jaren geleden
bovenliggende
commit
3fda8ec5c2

+ 48 - 8
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Configuration;
+using System.Collections.Generic;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
@@ -345,6 +346,31 @@ namespace MediaBrowser.Api.LiveTv
         public string Id { get; set; }
     }
 
+    [Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
+    [Authenticated]
+    public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
+    {
+    }
+
+    [Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
+    [Authenticated]
+    public class DeleteListingProvider : IReturnVoid
+    {
+        [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")]
+        public string Id { get; set; }
+    }
+
+    [Route("/LiveTv/ListingProviders/Lineups", "GET", Summary = "Gets available lineups")]
+    [Authenticated]
+    public class GetLineups : IReturn<List<NameIdPair>>
+    {
+        [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string Id { get; set; }
+
+        [ApiMember(Name = "Location", Description = "Location", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string Location { get; set; }
+    }
+
     public class LiveTvService : BaseApiService
     {
         private readonly ILiveTvManager _liveTvManager;
@@ -373,20 +399,27 @@ namespace MediaBrowser.Api.LiveTv
             }
         }
 
-        public void Post(AddTunerHost request)
+        public object Post(AddListingProvider request)
+        {
+            var result = _liveTvManager.SaveListingProvider(request).Result;
+            return ToOptimizedResult(result);
+        }
+
+        public void Delete(DeleteListingProvider request)
         {
             var config = GetConfiguration();
 
-            config.TunerHosts.Add(new TunerHostInfo
-            {
-                Id = Guid.NewGuid().ToString("N"),
-                Url = request.Url,
-                Type = request.Type
-            });
+            config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList();
 
             _config.SaveConfiguration("livetv", config);
         }
 
+        public void Post(AddTunerHost request)
+        {
+            var task = _liveTvManager.SaveTunerHost(request);
+            Task.WaitAll(task);
+        }
+
         public void Delete(DeleteTunerHost request)
         {
             var config = GetConfiguration();
@@ -401,6 +434,13 @@ namespace MediaBrowser.Api.LiveTv
             return _config.GetConfiguration<LiveTvOptions>("livetv");
         }
 
+        public async Task<object> Get(GetLineups request)
+        {
+            var info = await _liveTvManager.GetLineups(request.Id, request.Location).ConfigureAwait(false);
+
+            return ToOptimizedSerializedResultUsingCache(info);
+        }
+
         public async Task<object> Get(GetLiveTvInfo request)
         {
             var info = await _liveTvManager.GetLiveTvInfo(CancellationToken.None).ConfigureAwait(false);

+ 5 - 1
MediaBrowser.Controller/LiveTv/IListingsProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Model.LiveTv;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.LiveTv;
 using System;
 using System.Collections.Generic;
 using System.Threading;
@@ -9,7 +10,10 @@ namespace MediaBrowser.Controller.LiveTv
     public interface IListingsProvider
     {
         string Name { get; }
+        string Type { get; }
         Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
         Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
+        Task Validate(ListingsProviderInfo info);
+        Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location);
     }
 }

+ 23 - 2
MediaBrowser.Controller/LiveTv/ILiveTvManager.cs

@@ -56,12 +56,14 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="id">The identifier.</param>
         /// <returns>Task.</returns>
         Task CancelSeriesTimer(string id);
-        
+
         /// <summary>
         /// Adds the parts.
         /// </summary>
         /// <param name="services">The services.</param>
-        void AddParts(IEnumerable<ILiveTvService> services);
+        /// <param name="tunerHosts">The tuner hosts.</param>
+        /// <param name="listingProviders">The listing providers.</param>
+        void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders);
 
         /// <summary>
         /// Gets the channels.
@@ -337,5 +339,24 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="dto">The dto.</param>
         /// <param name="user">The user.</param>
         void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, User user = null);
+        /// <summary>
+        /// Saves the tuner host.
+        /// </summary>
+        /// <param name="info">The information.</param>
+        /// <returns>Task.</returns>
+        Task SaveTunerHost(TunerHostInfo info);
+        /// <summary>
+        /// Saves the listing provider.
+        /// </summary>
+        /// <param name="info">The information.</param>
+        /// <returns>Task.</returns>
+        Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info);
+        /// <summary>
+        /// Gets the lineups.
+        /// </summary>
+        /// <param name="providerId">The provider identifier.</param>
+        /// <param name="location">The location.</param>
+        /// <returns>Task&lt;List&lt;NameIdPair&gt;&gt;.</returns>
+        Task<List<NameIdPair>> GetLineups(string providerId, string location);
     }
 }

+ 6 - 0
MediaBrowser.Controller/LiveTv/ITunerHost.cs

@@ -46,5 +46,11 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
         Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken);
+        /// <summary>
+        /// Validates the specified information.
+        /// </summary>
+        /// <param name="info">The information.</param>
+        /// <returns>Task.</returns>
+        Task Validate(TunerHostInfo info);
     }
 }

+ 3 - 2
MediaBrowser.Model/LiveTv/LiveTvOptions.cs

@@ -28,10 +28,11 @@ namespace MediaBrowser.Model.LiveTv
 
     public class ListingsProviderInfo
     {
-        public string ProviderName { get; set; }
+        public string Id { get; set; }
+        public string Type { get; set; }
         public string Username { get; set; }
         public string Password { get; set; }
-        public string ZipCode { get; set; }
         public string ListingsId { get; set; }
+        public string ZipCode { get; set; }
     }
 }

+ 6 - 8
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -30,18 +30,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
         private readonly ItemDataProvider<SeriesTimerInfo> _seriesTimerProvider;
         private readonly TimerManager _timerProvider;
 
-        private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>();
-        private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>();
+        private readonly LiveTvManager _liveTvManager;
 
-        public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config)
+        public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager)
         {
             _appHpst = appHost;
             _logger = logger;
             _httpClient = httpClient;
             _config = config;
+            _liveTvManager = (LiveTvManager)liveTvManager;
             _jsonSerializer = jsonSerializer;
-            _tunerHosts.AddRange(appHost.GetExports<ITunerHost>());
-            _listingProviders.AddRange(appHost.GetExports<IListingsProvider>());
 
             _recordingProvider = new ItemDataProvider<RecordingInfo>(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
             _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
@@ -76,7 +74,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             var status = new LiveTvServiceStatusInfo();
             var list = new List<LiveTvTunerInfo>();
 
-            foreach (var host in _tunerHosts)
+            foreach (var host in _liveTvManager.TunerHosts)
             {
                 foreach (var hostInstance in host.GetTunerHosts())
                 {
@@ -104,7 +102,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
         {
             var list = new List<ChannelInfo>();
 
-            foreach (var host in _tunerHosts)
+            foreach (var host in _liveTvManager.TunerHosts)
             {
                 foreach (var hostInstance in host.GetTunerHosts())
                 {
@@ -288,7 +286,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             return GetConfiguration().ListingProviders
                 .Select(i =>
                 {
-                    var provider = _listingProviders.FirstOrDefault(l => string.Equals(l.Name, i.ProviderName, StringComparison.OrdinalIgnoreCase));
+                    var provider = _liveTvManager.ListingProviders.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase));
 
                     return provider == null ? null : new Tuple<IListingsProvider, ListingsProviderInfo>(provider, i);
                 })

+ 43 - 30
MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -422,7 +422,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
             return images;
         }
 
-        public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, CancellationToken cancellationToken)
+        public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, string location, CancellationToken cancellationToken)
         {
             var token = await GetToken(info, cancellationToken);
 
@@ -437,7 +437,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
 
             var options = new HttpRequestOptions()
             {
-                Url = ApiUrl + "/headends?country=USA&postalcode=" + info.ZipCode,
+                Url = ApiUrl + "/headends?country=USA&postalcode=" + location,
                 UserAgent = UserAgent,
                 CancellationToken = cancellationToken
             };
@@ -484,43 +484,43 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
 
         private async Task<string> GetToken(ListingsProviderInfo info, CancellationToken cancellationToken)
         {
-            await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-            try
-            {
-                var username = info.Username;
+            var username = info.Username;
 
-                // Reset the token if there's no username
-                if (string.IsNullOrWhiteSpace(username))
-                {
-                    return null;
-                }
+            // Reset the token if there's no username
+            if (string.IsNullOrWhiteSpace(username))
+            {
+                return null;
+            }
 
-                var password = info.Password;
-                if (string.IsNullOrWhiteSpace(password))
-                {
-                    return null;
-                }
+            var password = info.Password;
+            if (string.IsNullOrWhiteSpace(password))
+            {
+                return null;
+            }
 
-                NameValuePair savedToken = null;
-                if (!_tokens.TryGetValue(username, out savedToken))
-                {
-                    savedToken = new NameValuePair();
-                    _tokens.TryAdd(username, savedToken);
-                }
+            NameValuePair savedToken = null;
+            if (!_tokens.TryGetValue(username, out savedToken))
+            {
+                savedToken = new NameValuePair();
+                _tokens.TryAdd(username, savedToken);
+            }
 
-                if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value))
+            if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value))
+            {
+                long ticks;
+                if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks))
                 {
-                    long ticks;
-                    if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks))
+                    // If it's under 24 hours old we can still use it
+                    if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks)
                     {
-                        // If it's under 24 hours old we can still use it
-                        if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks)
-                        {
-                            return savedToken.Name;
-                        }
+                        return savedToken.Name;
                     }
                 }
+            }
 
+            await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+            try
+            {
                 var result = await GetTokenInternal(username, password, cancellationToken).ConfigureAwait(false);
                 savedToken.Name = result;
                 savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture);
@@ -563,6 +563,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
             get { return "Schedules Direct"; }
         }
 
+        public string Type
+        {
+            get { return "SchedulesDirect"; }
+        }
+
         public class ScheduleDirect
         {
             public class Token
@@ -842,5 +847,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
 
         }
 
+        public async Task Validate(ListingsProviderInfo info)
+        {
+        }
+
+        public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location)
+        {
+            return GetHeadends(info, location, CancellationToken.None);
+        }
     }
 }

+ 97 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -57,6 +57,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         private readonly ConcurrentDictionary<Guid, Guid> _refreshedPrograms = new ConcurrentDictionary<Guid, Guid>();
 
+        private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>();
+        private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>();
+
         public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager)
         {
             _config = config;
@@ -92,9 +95,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         /// Adds the parts.
         /// </summary>
         /// <param name="services">The services.</param>
-        public void AddParts(IEnumerable<ILiveTvService> services)
+        /// <param name="tunerHosts">The tuner hosts.</param>
+        /// <param name="listingProviders">The listing providers.</param>
+        public void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders)
         {
             _services.AddRange(services);
+            _tunerHosts.AddRange(tunerHosts);
+            _listingProviders.AddRange(listingProviders);
 
             foreach (var service in _services)
             {
@@ -102,6 +109,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             }
         }
 
+        public List<ITunerHost> TunerHosts
+        {
+            get { return _tunerHosts; }
+        }
+
+        public List<IListingsProvider> ListingProviders
+        {
+            get { return _listingProviders; }
+        }
+
         void service_DataSourceChanged(object sender, EventArgs e)
         {
             _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
@@ -2154,5 +2171,84 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             var user = _userManager.GetUserById(userId);
             return await _libraryManager.GetNamedView(user, name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false);
         }
+
+        public async Task SaveTunerHost(TunerHostInfo info)
+        {
+            info = (TunerHostInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(TunerHostInfo));
+            
+            var provider = _tunerHosts.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase));
+
+            if (provider == null)
+            {
+                throw new ResourceNotFoundException();
+            }
+
+            await provider.Validate(info).ConfigureAwait(false);
+
+            var config = GetConfiguration();
+
+            var index = config.TunerHosts.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
+
+            if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
+            {
+                info.Id = Guid.NewGuid().ToString("N");
+                config.TunerHosts.Add(info);
+            }
+            else
+            {
+                config.TunerHosts[index] = info;
+            }
+
+            _config.SaveConfiguration("livetv", config);
+        }
+
+        public async Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info)
+        {
+            info = (ListingsProviderInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(ListingsProviderInfo));
+
+            var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase));
+
+            if (provider == null)
+            {
+                throw new ResourceNotFoundException();
+            }
+
+            await provider.Validate(info).ConfigureAwait(false);
+
+            var config = GetConfiguration();
+
+            var index = config.ListingProviders.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
+
+            if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
+            {
+                info.Id = Guid.NewGuid().ToString("N");
+                config.ListingProviders.Add(info);
+            }
+            else
+            {
+                config.ListingProviders[index] = info;
+            }
+
+            _config.SaveConfiguration("livetv", config);
+
+            return info;
+        }
+
+
+        public Task<List<NameIdPair>> GetLineups(string providerId, string location)
+        {
+            var config = GetConfiguration();
+
+            var info = config.ListingProviders.FirstOrDefault(i => string.Equals(i.Id, providerId, StringComparison.OrdinalIgnoreCase));
+
+            var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase));
+
+            if (provider == null)
+            {
+                throw new ResourceNotFoundException();
+            }
+
+            return provider.GetLineups(info, location);
+        }
     }
 }

+ 6 - 2
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs

@@ -3,7 +3,6 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
@@ -15,7 +14,6 @@ using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
 
 namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
 {
@@ -222,5 +220,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
             } 
             throw new ApplicationException("Channel not found.");
         }
+
+
+        public async Task Validate(TunerHostInfo info)
+        {
+            await GetChannels(info, CancellationToken.None).ConfigureAwait(false);
+        }
     }
 }

+ 8 - 0
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs

@@ -185,5 +185,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
             {
             }
         }
+
+        public async Task Validate(TunerHostInfo info)
+        {
+            if (!File.Exists(info.Url))
+            {
+                throw new FileNotFoundException();
+            }
+        }
     }
 }

+ 4 - 1
MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json

@@ -820,5 +820,8 @@
     "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?",
     "MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?",
     "HeaderDeleteProvider": "Delete Provider",
-    "HeaderAddProvider": "Add Provider"
+    "HeaderAddProvider": "Add Provider",
+    "ErrorAddingTunerDevice": "There was an error adding the tuner device. Please ensure it is accessible and try again.",
+    "ErrorSavingTvProvider": "There was an error saving the TV provider. Please ensure it is accessible and try again.",
+    "ErrorGettingTvLineups": "There was an error downloading tv lineups. Please ensure your username and password are correct and try again."
 }

+ 4 - 1
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -1483,5 +1483,8 @@
     "TabTuners": "Tuners",
     "HeaderGuideProviders": "Guide Providers",
     "AddGuideProviderHelp": "Add a source for TV Guide information",
-    "LabelZipCode": "Zip Code"
+    "LabelZipCode": "Zip Code:",
+    "GuideProviderListingsStep": "Step 2: Select Listings",
+    "GuideProviderLoginStep": "Step 1: Login",
+    "LabelLineup": "Lineup"
 }

+ 1 - 1
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -784,7 +784,7 @@ namespace MediaBrowser.Server.Startup.Common
 
             ImageProcessor.AddParts(GetExports<IImageEnhancer>());
 
-            LiveTvManager.AddParts(GetExports<ILiveTvService>());
+            LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
 
             SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
             ChapterManager.AddParts(GetExports<IChapterProvider>());

+ 2 - 2
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -183,7 +183,7 @@
     <Content Include="dashboard-ui\livetvguide.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="dashboard-ui\livetvguidesettings.html">
+    <Content Include="dashboard-ui\livetvguideprovider-scd.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Content Include="dashboard-ui\livetvrecordings.html">
@@ -207,7 +207,7 @@
     <Content Include="dashboard-ui\scripts\homeupcoming.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="dashboard-ui\scripts\livetvguidesettings.js">
+    <Content Include="dashboard-ui\scripts\livetvguideprovider-scd.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Content Include="dashboard-ui\scripts\mypreferenceshome.js">