diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs index b37a0d8..999f8dc 100644 --- a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs @@ -70,21 +70,21 @@ namespace SDL2Demo.Jobs object[] previousSettings = dataStorage.GetLastUiBlindscanSettings(); if (previousSettings != null) { - settingsWindowBLScanTunerSelection = (int)previousSettings[1]; - settingsWindowUseDifferentTunerForSetFilter = (bool)previousSettings[2]; - settingsWindowSetFilterTunerSelection = (int)previousSettings[3]; - settingsWindowDiseqc = (int)previousSettings[4]; - settingsWindowCollectIqGraphs = (bool)previousSettings[5]; - settingsWindowCollectRfSpectrum = (bool)previousSettings[6]; - settingsWindowCaptureFile = (bool)previousSettings[7]; - settingsWindowSatellite = (int)previousSettings[8]; - settingsWindowLNB = (int)previousSettings[9]; - settingsWindowDish = (int)previousSettings[10]; + settingsWindowBLScanTunerSelection = Convert.ToInt32(previousSettings[1]); + settingsWindowUseDifferentTunerForSetFilter = Convert.ToBoolean(previousSettings[2]); + settingsWindowSetFilterTunerSelection = Convert.ToInt32(previousSettings[3]); + settingsWindowDiseqc = Convert.ToInt32(previousSettings[4]); + settingsWindowCollectIqGraphs = Convert.ToBoolean(previousSettings[5]); + settingsWindowCollectRfSpectrum = Convert.ToBoolean(previousSettings[6]); + settingsWindowCaptureFile = Convert.ToBoolean(previousSettings[7]); + settingsWindowSatellite = Convert.ToInt32(previousSettings[8]); + settingsWindowLNB = Convert.ToInt32(previousSettings[9]); + settingsWindowDish = Convert.ToInt32(previousSettings[10]); - settingsWindowScanHorizontalLow = (bool)previousSettings[11]; - settingsWindowScanHorizontalHigh = (bool)previousSettings[12]; - settingsWindowScanVerticalLow = (bool)previousSettings[13]; - settingsWindowScanVerticalHigh = (bool)previousSettings[14]; + settingsWindowScanHorizontalLow = Convert.ToBoolean(previousSettings[11]); + settingsWindowScanHorizontalHigh = Convert.ToBoolean(previousSettings[12]); + settingsWindowScanVerticalLow = Convert.ToBoolean(previousSettings[13]); + settingsWindowScanVerticalHigh = Convert.ToBoolean(previousSettings[14]); } } public bool IsWindowOpen() @@ -113,7 +113,7 @@ namespace SDL2Demo.Jobs bjc.SatellitePosition = satellites[settingsWindowSatellite]; if (settingsWindowUseDifferentTunerForSetFilter) - bjc.StreamReader = new CoopBlindscanStreamReader(streamReader, settingsWindowBLScanTunerSelection, settingsWindowSetFilterTunerSelection); + bjc.StreamReader = new CoopBlindscanStreamReaderProxy(streamReader, settingsWindowBLScanTunerSelection, settingsWindowSetFilterTunerSelection); else bjc.StreamReader = streamReader; @@ -128,6 +128,11 @@ namespace SDL2Demo.Jobs { if (ImGui.Begin("Blindscan", ref windowOpen, ImGuiWindowFlags.AlwaysAutoResize)) { + if (satellites.Count == 0) + { + ImGui.Text("You didn't configure the sattelite positions yet."); + return; + } ImGui.PushID("tunerA"); if (ImGui.BeginCombo("Tuner for BLScanEx and RFScan", tuners[settingsWindowBLScanTunerSelection].Name)) { diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs index 60f6c35..8c50f32 100644 --- a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs @@ -1038,7 +1038,6 @@ namespace SDL2Demo.Jobs public void NotifyWss(ushort programNumber, WssDataBlock wssDataBlock) { - throw new NotImplementedException(); } #region Stream Type Autodetection @@ -1460,9 +1459,10 @@ namespace SDL2Demo.Jobs throw new NotImplementedException(); } + private bool gseMode; public void SetGseMode() { - throw new NotImplementedException(); + gseMode = true; } #region Framegrabs diff --git a/GUIs/skyscraper8.UI.ImGui/Program.cs b/GUIs/skyscraper8.UI.ImGui/Program.cs index 5c30abe..29ad78a 100644 --- a/GUIs/skyscraper8.UI.ImGui/Program.cs +++ b/GUIs/skyscraper8.UI.ImGui/Program.cs @@ -754,8 +754,9 @@ namespace SkyscraperUI { InheritedBlindscanJob inheritedBlindscanJob = new InheritedBlindscanJob(jobConfiguration); EnrollJob(inheritedBlindscanJob); - inheritedBlindscanWindow = null; } + + inheritedBlindscanWindow = null; } } diff --git a/skyscraper8/Dvb/Descriptors/Extension/0x00_ImageIconDescriptor.cs b/skyscraper8/Dvb/Descriptors/Extension/0x00_ImageIconDescriptor.cs new file mode 100644 index 0000000..6a23586 --- /dev/null +++ b/skyscraper8/Dvb/Descriptors/Extension/0x00_ImageIconDescriptor.cs @@ -0,0 +1,112 @@ +using skyscraper5.Dvb; +using skyscraper5.Skyscraper.Plugins; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Skyscraper; +using skyscraper5.Skyscraper.IO; + +namespace skyscraper8.Dvb.Descriptors.Extension +{ + [SkyscraperPlugin] + [ExtensionDescriptor(0x00, "NIT","BAT","SDT","EIT","SIT")] + public class _0x00_ImageIconDescriptor : skyscraper5.Dvb.ExtensionDescriptor + { + public _0x00_ImageIconDescriptor(byte[] buffer) + { + MemoryStream ms = new MemoryStream(buffer, false); + byte byteA = ms.ReadUInt8(); + DescriptiorNumber = (byteA & 0x80) >> 4; + LastDescriptorNumber = (byteA & 0x08); + + byte byteB = ms.ReadUInt8(); + int reservedFutureUse = (byteB & 0xf8); + IconId = (byteB & 0x07); + if (DescriptiorNumber == 0x00) + { + byte byteC = ms.ReadUInt8(); + IconTransportMode = (byteC & 0xc0) >> 6; + bool positionFlag = (byteC & 0x20) != 0; + if (positionFlag) + { + CoordinateSystem = (byteC & 0x1c); + reservedFutureUse = (byteC & 0x03); + byte byteD = ms.ReadUInt8(); + byte byteE = ms.ReadUInt8(); + byte byteF = ms.ReadUInt8(); + IconHorizontalOrigin = (byteD << 4); + IconHorizontalOrigin += ((byteE & 0xf0) >> 4); + IconVerticalOrigin = ((byteE & 0x0f) << 8); + IconVerticalOrigin += byteF; + } + else + { + reservedFutureUse = (byteC & 0x1f); + } + + byte iconTypeLength = ms.ReadUInt8(); + if (ms.GetAvailableBytes() < iconTypeLength) + { + Valid = false; + return; + } + + IconType = ms.ReadUTF8FixedLength(iconTypeLength); + if (IconTransportMode == 0) + { + byte iconDataLength = ms.ReadUInt8(); + if (ms.GetAvailableBytes() < iconDataLength) + { + Valid = false; + return; + } + IconData = ms.ReadBytes(iconDataLength); + } + else if (IconTransportMode == 1) + { + byte urlLength = ms.ReadUInt8(); + if (ms.GetAvailableBytes() < urlLength) + { + Valid = false; + return; + } + Url = ms.ReadUTF8FixedLength(urlLength); + } + } + else + { + byte iconDataLength = ms.ReadUInt8(); + if (ms.GetAvailableBytes() < iconDataLength) + { + Valid = false; + return; + } + IconData = ms.ReadBytes(iconDataLength); + } + + Valid = true; + } + + public int IconId { get; set; } + + public string Url { get; set; } + + public byte[] IconData { get; set; } + + public string IconType { get; set; } + + public int? IconVerticalOrigin { get; set; } + + public int? IconHorizontalOrigin { get; set; } + + public int? CoordinateSystem { get; set; } + + public int? IconTransportMode { get; set; } + + public int LastDescriptorNumber { get; set; } + + public int DescriptiorNumber { get; set; } + } +} diff --git a/skyscraper8/Dvb/Psi/EitParser.cs b/skyscraper8/Dvb/Psi/EitParser.cs index 6752843..c10bf15 100644 --- a/skyscraper8/Dvb/Psi/EitParser.cs +++ b/skyscraper8/Dvb/Psi/EitParser.cs @@ -9,6 +9,7 @@ using skyscraper5.Mpeg2; using skyscraper5.Mpeg2.Descriptors; using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.Plugins; +using skyscraper8.Dvb.Descriptors.Extension; namespace skyscraper5.Dvb.Psi { @@ -215,7 +216,28 @@ namespace skyscraper5.Dvb.Psi output.DoNotApplyRevocation = fsnd.DoNotApplyRevocation; output.DoNotScramble = fsnd.DoNotScramble; break; - default: + case nameof(_0x00_ImageIconDescriptor): + _0x00_ImageIconDescriptor iid = (_0x00_ImageIconDescriptor)dvbDescriptor; + if (iid.LastDescriptorNumber != 0) + { + if (output.IconComponents == null) + { + output.IconComponents = new _0x00_ImageIconDescriptor[iid.LastDescriptorNumber]; + } + output.IconComponents[iid.DescriptiorNumber] = iid; + } + else + { + output.IconUrl = iid.Url; + output.IconData = iid.IconData; + output.IconType = iid.IconType; + output.IconVerticalOrigin = iid.IconVerticalOrigin; + output.IconHorizontalOrigin = iid.IconHorizontalOrigin; + output.IconCoordinateSystem = iid.CoordinateSystem; + output.IconTransportMode = iid.IconTransportMode; + } + break; + default: throw new NotImplementedException(name); } } diff --git a/skyscraper8/Dvb/Psi/Model/EitEvent.cs b/skyscraper8/Dvb/Psi/Model/EitEvent.cs index 317e116..806074c 100644 --- a/skyscraper8/Dvb/Psi/Model/EitEvent.cs +++ b/skyscraper8/Dvb/Psi/Model/EitEvent.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using skyscraper5.Dvb.Descriptors; +using skyscraper8.Dvb.Descriptors.Extension; namespace skyscraper5.Dvb.Psi.Model { @@ -82,8 +83,18 @@ namespace skyscraper5.Dvb.Psi.Model public bool? DoNotApplyRevocation { get; set; } public bool? DoNotScramble { get; set; } + //Image Icon Descriptor + public _0x00_ImageIconDescriptor[] IconComponents { get; set; } + public string IconUrl { get; set; } + public byte[] IconData { get; set; } + public string IconType { get; set; } + public int? IconVerticalOrigin { get; set; } + public int? IconHorizontalOrigin { get; set; } + public int? IconCoordinateSystem { get; set; } + public int? IconTransportMode { get; set; } - public EitEvent(ushort serviceId, ushort transportStreamId, ushort originalNetworkId) + + public EitEvent(ushort serviceId, ushort transportStreamId, ushort originalNetworkId) { ServiceId = serviceId; TransportStreamId = transportStreamId; diff --git a/skyscraper8/DvbNip/DvbNipEventHandler.cs b/skyscraper8/DvbNip/DvbNipEventHandler.cs index 7fa2403..15d9347 100644 --- a/skyscraper8/DvbNip/DvbNipEventHandler.cs +++ b/skyscraper8/DvbNip/DvbNipEventHandler.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; using moe.yo3explorer.skyscraper8.DVBI.Model; @@ -23,5 +24,6 @@ namespace skyscraper8.DvbNip void OnTimeOffsetFile(NipActualCarrierInformation currentCarrierInformation, TimeOffsetFileType timeOffsetFile); void OnNetworkInformationFile(NipActualCarrierInformation currentCarrierInformation, NetworkInformationFileType networkInformationFile); void OnServiceInformationFile(NipActualCarrierInformation currentCarrierInformation, ServiceInformationFileType serviceInformationFile); + void FluteFileAnnouncement(IPAddress ip, ushort port, FDTInstanceType flute); } } diff --git a/skyscraper8/DvbNip/DvbNipReceiver.cs b/skyscraper8/DvbNip/DvbNipReceiver.cs index 346dc3c..408ea7d 100644 --- a/skyscraper8/DvbNip/DvbNipReceiver.cs +++ b/skyscraper8/DvbNip/DvbNipReceiver.cs @@ -103,6 +103,7 @@ namespace skyscraper8.DvbNip if (isValidXml) { FDTInstanceType fdtAnnouncement = FluteUtilities.UnpackFluteFdt(fluteStream); + EventHandler.FluteFileAnnouncement(fluteCoordinate.Item1, fluteCoordinate.Item2, fdtAnnouncement); if (fdtAnnouncement != null) { SetFileAssociations(fluteListener, fdtAnnouncement); @@ -119,6 +120,7 @@ namespace skyscraper8.DvbNip } if (fluteListener.FileAssociation.ContentLocation.StartsWith("urn:dvb:")) { + EventHandler?.FluteFileArrival(CurrentCarrierInformation, fluteListener); HandleMetadata(fluteListener); fluteListener.Disabled = true; return; @@ -215,7 +217,6 @@ namespace skyscraper8.DvbNip throw new NotImplementedException(fluteListener.FileAssociation.ContentLocation); } } - private void TryPruneCache() { DateTime now = DateTime.Now; @@ -242,7 +243,6 @@ namespace skyscraper8.DvbNip } } } - private bool SetFileAssociations(FluteListener sourceListener, FDTInstanceType fdtAnnouncement) { bool result = false; diff --git a/skyscraper8/HlsProxy.cs b/skyscraper8/HlsProxy.cs new file mode 100644 index 0000000..2d1a770 --- /dev/null +++ b/skyscraper8/HlsProxy.cs @@ -0,0 +1,77 @@ +using log4net; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8 +{ + internal class HlsProxy + { + private readonly DirectoryInfo _sourceDirectory; + private readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public HlsProxy(DirectoryInfo sourceDirectory) + { + _sourceDirectory = sourceDirectory; + } + + public void Run() + { + if (!_sourceDirectory.Exists) + { + logger.FatalFormat("{0} does not exist.", _sourceDirectory.FullName); + return; + } + + if (_sourceDirectory.GetFiles("*.ts").Length == 0) + { + logger.FatalFormat("{0} does not contain any TS files.", _sourceDirectory.FullName); + return; + } + + Process process = new Process(); + process.StartInfo = new ProcessStartInfo("vlc"); + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.Arguments = "-"; + process.StartInfo.UseShellExecute = false; + process.Start(); + + HashSet knownFiles = new HashSet(); + + while (true) + { + if (process.HasExited) + break; + + FileInfo[] fileInfos = _sourceDirectory.GetFiles("*.ts"); + Array.Sort(fileInfos, (x, y) => x.Name.CompareTo(y.Name)); + + bool outputted = false; + for (int i = 0; i < fileInfos.Length; i++) + { + if (!knownFiles.Contains(fileInfos[i].Name)) + { + logger.InfoFormat("Outputting {0}", fileInfos[i].Name); + byte[] readAllBytes = File.ReadAllBytes(fileInfos[i].FullName); + process.StandardInput.BaseStream.Write(readAllBytes, 0, readAllBytes.Length); + process.StandardInput.BaseStream.Flush(); + knownFiles.Add(fileInfos[i].Name); + outputted = true; + break; + } + } + + if (!outputted) + { + logger.Info("No new HLS segment yet."); + } + + Thread.Sleep(1000); + } + } + } +} diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index 18d98af..cccc75f 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -26,8 +26,10 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Runtime.InteropServices; using skyscraper5.Skyscraper.Scraper.StreamAutodetection; +using skyscraper8; using skyscraper8.SatIp; using skyscraper8.SatIp.RtspResponses; +using skyscraper8.SimpleServiceDiscoveryProtocol; [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config")] namespace skyscraper5 @@ -37,10 +39,11 @@ namespace skyscraper5 private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); private static void IntegrationTest() { - RtspClient rtspClient = new RtspClient("172.20.20.121", 554); + //List ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList(); + /*RtspClient rtspClient = new RtspClient("172.20.20.121", 554); rtspClient.AutoReconnect = true; RtspOptionsResponse options = rtspClient.GetOptions("/"); - string url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11954, true, 27500); + string url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11141, true, 23500); RtspDescribeResponse describe = rtspClient.GetDescribe(url); SessionDescriptionProtocol sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol(); @@ -61,9 +64,9 @@ namespace skyscraper5 Console.WriteLine("{0} RTCPs",rtcps); Console.WriteLine("{0} RTPs",rtps); - Thread.Sleep(1000); + Thread.Sleep(1000);*/ - url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_VERTICAL, 10758, true, 22000); + /*url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11141, true, 23500); describe = rtspClient.GetDescribe(url); sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol(); @@ -83,8 +86,8 @@ namespace skyscraper5 rtspClient.AutoReconnect = false; rtspClient.GetTeardown(setup); Console.WriteLine("{0} RTCPs", rtcps); - Console.WriteLine("{0} RTPs", rtps); - rtspClient.Dispose(); + Console.WriteLine("{0} RTPs", rtps);*/ + //rtspClient.Dispose(); } static void Main(string[] args) @@ -257,16 +260,30 @@ namespace skyscraper5 Program.HandleFileToLiveSystem(args[1]); return; } + + if (args[0].ToLowerInvariant().Equals("hlsproxy")) + { + DirectoryInfo di = new DirectoryInfo(args[1]); + HlsProxy hlsproxy = new HlsProxy(di); + hlsproxy.Run(); + return; + } } - Passing passing = new Passing(); + /*Passing passing = new Passing(); if (!passing.Boot()) { Environment.Exit(1); return; } - passing.Run(); - } + passing.Run();*/ + Console.WriteLine("You're not supposed to run me directly. Run me from the commandline using the following:"); + Console.WriteLine("for example: .\\skyscraper8.exe cscan tcp://127.0.0.1:6969"); + Console.WriteLine(" or: .\\skyscraper8.exe \"C:\\path\\to\\file.ts\\"); + Console.WriteLine(); + Console.WriteLine("Bonus feature:"); + Console.WriteLine(".\\skyscraper8.exe hlsproxy \"C:\\path\\to\\hls\\files\\\" - to pipe a HLS stream from a local directory into VLC."); + } private static void ProcessDirectory(DirectoryInfo di) { diff --git a/skyscraper8/Properties/launchSettings.json b/skyscraper8/Properties/launchSettings.json index bf60e0a..d79f1dc 100644 --- a/skyscraper8/Properties/launchSettings.json +++ b/skyscraper8/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "skyscraper8": { "commandName": "Project", - "commandLineArgs": "file-live \"C:\\Temp\\11881_v_20250810_1548.ts\"", + "commandLineArgs": "\"C:\\devel\\skyscraper8\\skyscraper8\\bin\\Debug\\net8.0\\36E-12226L.ts\"", "remoteDebugEnabled": false }, "Container (Dockerfile)": { diff --git a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs new file mode 100644 index 0000000..9d75bb6 --- /dev/null +++ b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs @@ -0,0 +1,120 @@ +using log4net; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.SimpleServiceDiscoveryProtocol +{ + internal class SsdpClient + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + private const string SEARCH_STRING = + "M-SEARCH * HTTP/1.1\r\n" + + "HOST:239.255.255.250:1900\r\n" + + "MAN:\"ssdp:discover\"\r\n" + + "ST:ssdp:all\r\n" + + "MX:3\r\n\r\n"; + + public static IEnumerable GetSsdpDevices(int timeout) + { + NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); + IPAddress[] ipAddresses = Array.ConvertAll(networkInterfaces, x => GetIPAddress(x)); + IPEndPoint[] localEndPoints = Array.ConvertAll(ipAddresses, x => new IPEndPoint(x, 1901)); + IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900); + Socket[] udpSockets = Array.ConvertAll(localEndPoints, + x => + { + byte[] addressBytes = x.Address.GetAddressBytes(); + if (addressBytes[0] == 169) + return null; + Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + temp.Bind(x); + temp.SendTo(Encoding.UTF8.GetBytes(SEARCH_STRING), SocketFlags.None, remoteEndPoint); + return temp; + }); + + byte[] buffer = new byte[1600]; + int recvBytes = 0; + DateTime timeStarted = DateTime.Now; + while (true) + { + for (int i = 0; i < udpSockets.Length; i++) + { + if (udpSockets[i] == null) + continue; + + Array.Clear(buffer); + recvBytes = 0; + if (udpSockets[i].Available > 0) + { + recvBytes = udpSockets[i].Receive(buffer, SocketFlags.None); + if (recvBytes > 0) + { + string s = Encoding.UTF8.GetString(buffer, 0, recvBytes); + Console.WriteLine(s); + yield return new SsdpDevice(s); + } + } + } + + Thread.Sleep(1); + if ((DateTime.Now - timeStarted).TotalMilliseconds >= timeout) + break; + } + yield break; + } + + private static IPAddress GetIPAddress(NetworkInterface networkInterface) + { + IPInterfaceProperties ipProperties = networkInterface.GetIPProperties(); + UnicastIPAddressInformationCollection addresses = ipProperties.UnicastAddresses; + UnicastIPAddressInformation[] addressArray = addresses.ToArray(); + Array.Sort(addressArray, (a, b) => RateIpAddress(b).CompareTo(RateIpAddress(a))); + UnicastIPAddressInformation address = addressArray[0]; + return address.Address; + } + + private static int RateIpAddress(UnicastIPAddressInformation address) + { + IPAddress ipAddress = address.Address; + byte[] addressBytes = ipAddress.GetAddressBytes(); + if (addressBytes.Length == 0x10 && addressBytes[0] == 0xfe && addressBytes[1] == 0x80) + { + return 1; //Link local IPv6 is okay, but we prefer IPv4. + } + + if (addressBytes.Length == 4 && addressBytes[0] == 169 && addressBytes[1] == 254) + { + return 2; //Auto-Assigned Link-Local IPv4, this is okay, + } + + if (addressBytes.Length == 4 && addressBytes[0] == 192 && addressBytes[1] == 168) + { + return 3; //A non-auto-assigned Link-Local. This is what we want. + } + + if (addressBytes.Length == 4 && addressBytes[0] == 172 && (addressBytes[1] >= 16 && addressBytes[1] <= 31)) + { + return 3; //A non-auto-assigned Link-Local. This is what we want. + } + + if (addressBytes.Length == 4 && addressBytes[0] == 127) + { + return Int32.MinValue + 1; //A loopback address. We don't want these. + } + + if (addressBytes.Length == 16 && addressBytes[0] == 0 && addressBytes[15] == 1) + { + return Int32.MinValue; //An IPv6 loopback. That's even less wanted. + } + logger.WarnFormat("Don't know how to rate IP address", address.Address.ToString()); + return Int32.MinValue; + } + } +} diff --git a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpDevice.cs b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpDevice.cs new file mode 100644 index 0000000..6adaaa7 --- /dev/null +++ b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpDevice.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.SimpleServiceDiscoveryProtocol +{ + internal class SsdpDevice + { + public SsdpDevice(string notification) + { + StringReader sr = new StringReader(notification); + throw new NotImplementedException(notification); + } + } +} diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReader.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReaderProxy.cs similarity index 69% rename from skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReader.cs rename to skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReaderProxy.cs index 306713c..85e4568 100644 --- a/skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReader.cs +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/CoopBlindscanStreamReaderProxy.cs @@ -3,22 +3,63 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using log4net; using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.IO.CrazycatStreamReader; namespace skyscraper8.Skyscraper.FrequencyListGenerator { - public class CoopBlindscanStreamReader : IStreamReader + public class CoopBlindscanStreamReaderProxy : IStreamReader { + private static ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + private readonly IStreamReader _proxiedStreamReader; private readonly int _blindScanTuner; private readonly int _setFilterTuner; - public CoopBlindscanStreamReader(IStreamReader proxiedStreamReader, int blindScanTuner, int setFilterTuner) + private int currentlySelectedTuner; + private uint lastDiseqcType; + private DiSEqC_Opcode lastDiseqcOpcode; + public CoopBlindscanStreamReaderProxy(IStreamReader proxiedStreamReader, int blindScanTuner, int setFilterTuner) { _proxiedStreamReader = proxiedStreamReader; _blindScanTuner = blindScanTuner; _setFilterTuner = setFilterTuner; + currentlySelectedTuner = -1; + lastDiseqcType = UInt32.MaxValue; + + if (logger == null) + { + logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + logger.Debug("We'll be using two tuners for this operation."); + } + } + + private bool SwitchTuner(int targetTuner) + { + if (targetTuner == currentlySelectedTuner) + return true; + + if (logger == null) + logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + logger.Info(String.Format("Switching tuner to #{0}", targetTuner)); + if (currentlySelectedTuner != -1) + { + if (!_proxiedStreamReader.StopDVB()) + return false; + } + + if (!_proxiedStreamReader.StartDvbEx(targetTuner)) + return false; + + if (lastDiseqcType != uint.MaxValue) + { + if (!_proxiedStreamReader.SendDiSEqC(lastDiseqcType, lastDiseqcOpcode)) + return false; + } + + currentlySelectedTuner = targetTuner; + return true; } public void Dispose() @@ -48,7 +89,16 @@ namespace skyscraper8.Skyscraper.FrequencyListGenerator public bool StartDvbEx(int index) { - throw new NotImplementedException(); + bool result = _proxiedStreamReader.StartDvbEx(index); + if (result) + { + currentlySelectedTuner = index; + } + else + { + currentlySelectedTuner = -1; + } + return result; } public bool StopDVB() @@ -63,7 +113,14 @@ namespace skyscraper8.Skyscraper.FrequencyListGenerator public bool SendDiSEqC(uint diseqcType, DiSEqC_Opcode data) { - throw new NotImplementedException(); + bool result = _proxiedStreamReader.SendDiSEqC(diseqcType, data); + if (result) + { + lastDiseqcType = diseqcType; + lastDiseqcOpcode = data; + } + + return result; } public bool SendDiseqCmd(byte[] buffer, int length) @@ -78,7 +135,13 @@ namespace skyscraper8.Skyscraper.FrequencyListGenerator public bool SetChannel(int freq, int symbrate, int pol, VITERBIRATE_TYPE fec, int lof1, int lof2, int lofsw) { - throw new NotImplementedException(); + if (!SwitchTuner(_setFilterTuner)) + return false; + + if (!_proxiedStreamReader.SetChannel(freq, symbrate, pol, fec, lof1, lof2, lofsw)) + return false; + + return true; } public bool SetChannelEx(int freq, int symbrate, int pol, VITERBIRATE_TYPE fec, int lof1, int lof2, int lofsw, MOD_TYPE mod) @@ -94,7 +157,13 @@ namespace skyscraper8.Skyscraper.FrequencyListGenerator public bool SetFilter(int pid, StdcallDvbCallback func, int callbackType, int size, ref nint lpFilterNum) { - throw new NotImplementedException(); + if (!SwitchTuner(_setFilterTuner)) + return false; + + if (!_proxiedStreamReader.SetFilter(pid, func, callbackType, size, ref lpFilterNum)) + return false; + + return true; } public bool SetFilterEx(int pid, StdcallDvbCallbackEx lpFunc, int callbackType, int size, ref nint lpFilterNum) @@ -115,7 +184,7 @@ namespace skyscraper8.Skyscraper.FrequencyListGenerator public bool DelFilter(nint filterNum) { - throw new NotImplementedException(); + return _proxiedStreamReader.DelFilter(filterNum); } public bool GetSignal(ref int pStrength, ref int pQuality) @@ -155,7 +224,14 @@ namespace skyscraper8.Skyscraper.FrequencyListGenerator public bool RFScan(int freq, int pol, int lof1, int lof2, int lofsw, out double pRFLevel) { - throw new NotImplementedException(); + pRFLevel = double.NaN; + + if (!SwitchTuner(_blindScanTuner)) + return false; + + if (!_proxiedStreamReader.RFScan(freq, pol, lof1, lof2, lofsw, out pRFLevel)) + return false; + return true; } public bool FFTInit() @@ -178,23 +254,48 @@ namespace skyscraper8.Skyscraper.FrequencyListGenerator public bool BLScanEx(int freq, int freq_range, int pol, int lof1, int lof2, int lofsw, int minsr, STD_TYPE std, ref SearchResult pSearchResult) { - throw new NotImplementedException(); + if (!SwitchTuner(_setFilterTuner)) + return false; + + if (!_proxiedStreamReader.BLScanEx(freq, freq_range, pol, lof1, lof2, lofsw, minsr, std, ref pSearchResult)) + return false; + + return true; } public bool BLScan2(int freq_start, int freq_stop, int pol, int lof1, int lof2, int lofsw, nint pSearchResult, ref int pTpNum, BlScanCallback lpFunc) { - throw new NotImplementedException(); + if (!SwitchTuner(_blindScanTuner)) + return false; + + if (!_proxiedStreamReader.BLScan2(freq_start, freq_stop, pol, lof1, lof2, lofsw, pSearchResult, ref pTpNum, + lpFunc)) + return false; + + return true; } public bool SignalInfo(ref SearchResult pSearchResult) { - throw new NotImplementedException(); + if (!SwitchTuner(_setFilterTuner)) + return false; + + if (!_proxiedStreamReader.SignalInfo(ref pSearchResult)) + return false; + + return true; } public bool IQScan(uint input, sbyte[] pIQ, uint num) { - throw new NotImplementedException(); + if (!SwitchTuner(_setFilterTuner)) + return false; + + if (!_proxiedStreamReader.IQScan(input, pIQ, num)) + return false; + + return true; } public bool IQScan2(uint point, short[] pIQ, uint num) diff --git a/skyscraper8/Skyscraper/Scraper/FrameGrabber/ffmpegFrameGrabber.cs b/skyscraper8/Skyscraper/Scraper/FrameGrabber/ffmpegFrameGrabber.cs index 769d3d1..6c74844 100644 --- a/skyscraper8/Skyscraper/Scraper/FrameGrabber/ffmpegFrameGrabber.cs +++ b/skyscraper8/Skyscraper/Scraper/FrameGrabber/ffmpegFrameGrabber.cs @@ -40,7 +40,13 @@ namespace skyscraper5.Skyscraper.Scraper.FrameGrabber private void FrameGrabberThread() { - string outputPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".jpg"); + if (!CanStart()) + { + BusyFrameGrabbers--; + return; + } + + string outputPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".jpg"); IPEndPoint endpoint = TsProxyEndPoint; if (TsProxyEndPoint.Address.Equals(IPAddress.Any)) diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index a06e72b..f06bcda 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -61,7 +61,9 @@ using skyscraper5.Teletext.Wss; using skyscraper8.DvbI; using skyscraper8.DvbNip; using skyscraper8.Ietf.FLUTE; +using skyscraper8.Ietf.Rfc4236_ULE; using skyscraper8.Ses; +using skyscraper8.Skyscraper.Scraper.Storage; using skyscraper8.yo3explorer; using System; using System.Collections.Generic; @@ -72,9 +74,8 @@ using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; +using System.Security.Policy; using System.Text; -using skyscraper8.Ietf.Rfc4236_ULE; -using skyscraper8.Skyscraper.Scraper.Storage; using Tsubasa.IO; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; using RntParser = skyscraper5.Dvb.TvAnytime.RntParser; @@ -91,7 +92,7 @@ namespace skyscraper5.Skyscraper.Scraper { public const bool ALLOW_STREAM_TYPE_AUTODETECTION = true; public const bool ALLOW_FFMPEG_FRAMEGRABBER = true; - public const bool ENABLE_MPE_TO_PCAP = false; + public const bool ENABLE_MPE_TO_PCAP = true; private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); public TsContext DvbContext { get; } @@ -2498,7 +2499,14 @@ namespace skyscraper5.Skyscraper.Scraper string extension = Path.GetExtension(listener.FileAssociation.ContentLocation).ToLowerInvariant(); if (!DvbNipUtilities.IsContinuousFileType(extension)) LogEvent(SkyscraperContextEvent.FluteFileArrival, listener.FileAssociation.ContentLocation); - ObjectStorage.DvbNipFileArrival(carrier, listener); + else + { + IPEndPoint ep = new IPEndPoint(listener.DestinationAddress, listener.DestinationPort); + if (!knownNipSegments.ContainsKey(ep)) + knownNipSegments[ep] = new List(); + knownNipSegments[ep].Add(listener.FileAssociation.ContentLocation); + } + ObjectStorage.DvbNipFileArrival(carrier, listener); } public void OnMulticastGatewayConfiguration(NipActualCarrierInformation carrier, MulticastGatewayConfigurationType multicastGatewayConfiguration) @@ -2689,6 +2697,29 @@ namespace skyscraper5.Skyscraper.Scraper } } + private Dictionary> knownNipSegments; + private HashSet knownUrls; + public void FluteFileAnnouncement(IPAddress ip, ushort port, FDTInstanceType flute) + { + if (knownUrls == null) + { + knownUrls = new HashSet(); + knownNipSegments = new Dictionary>(); + } + + string url = flute.File[0].ContentLocation; + if (knownUrls.Contains(url)) + return; + + LogEvent(SkyscraperContextEvent.FluteFileAnnouncement, String.Format("{0}:{1} -> {2}", ip.ToString(), port, url)); + knownUrls.Add(url); + + IPEndPoint ep = new IPEndPoint(ip, port); + if (!knownNipSegments.ContainsKey(ep)) + knownNipSegments[ep] = new List(); + knownNipSegments[ep].Add(url); + } + public void FluteFileDownloadProgress(NipActualCarrierInformation currentCarrierInformation, ulong destinationTsi, ulong destinationToi, double progress, FileType filetype) { if (filetype != null) diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs index dbdaac3..d68fd97 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs @@ -80,6 +80,7 @@ DvbNipNetwork, DvbNipService, DvbNipMulticastSession, - DvbNipMulticastGatewayConfigurationTransportSession + DvbNipMulticastGatewayConfigurationTransportSession, + FluteFileAnnouncement } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs index b448e2a..f117fe5 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs @@ -1128,12 +1128,29 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, bool settingsWindowScanVerticalHigh) { - throw new NotImplementedException(); + object[] data = new object[] + { + DateTime.Now, + settingsWindowBlScanTunerSelection, settingsWindowUseDifferentTunerForSetFilter, + settingsWindowSetFilterTunerSelection, settingsWindowDiseqc, settingsWindowCollectIqGraphs, + settingsWindowCollectRfSpectrum, settingsWindowCaptureFile, settingsWindowSatellite, settingsWindowLnb, + dish, settingsWindowScanHorizontalLow, settingsWindowScanHorizontalHigh, + settingsWindowScanVerticalLow, settingsWindowScanVerticalHigh + }; + string path = Path.Combine(rootDirectory.FullName, "last_blindscan_settings.json"); + File.WriteAllText(path, JsonConvert.SerializeObject(data)); } public object[] GetLastUiBlindscanSettings() { - throw new NotImplementedException(); + string path = Path.Combine(rootDirectory.FullName, "last_blindscan_settings.json"); + if (File.Exists(path)) + { + object[] result = JsonConvert.DeserializeObject(File.ReadAllText(path)); + return result; + } + + return null; } public IEnumerable> SelectAllPmt() @@ -1477,12 +1494,24 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem public void StoreIqGraph(Guid jobGuid, long frequency, char polarity, IqChartData plot) { - throw new NotImplementedException(); + string filename = Path.Combine(rootDirectory.FullName, "iq", jobGuid.ToString(), frequency.ToString() + "_" + polarity + ".iq"); + FileInfo fi = new FileInfo(filename); + fi.Directory.EnsureExists(); + FileStream fileStream = fi.OpenWrite(); + plot.SaveTo(fileStream); + fileStream.Flush(true); + fileStream.Close(); } public void StoreRfSpectrum(Guid jobGuid, RfSpectrumData rfSpectrum) { - throw new NotImplementedException(); + string filename = Path.Combine(rootDirectory.FullName, "rf", jobGuid.ToString() + ".rf"); + FileInfo fi = new FileInfo(filename); + fi.Directory.EnsureExists(); + FileStream fileStream = fi.OpenWrite(); + rfSpectrum.SaveTo(fileStream); + fileStream.Flush(true); + fileStream.Close(); } public void DeleteIqGraph(Guid selectedGuid, int frequencyItem1, SatelliteDeliverySystemDescriptor.PolarizationEnum frequencyItem2) @@ -1495,30 +1524,74 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem throw new NotImplementedException(); } + class NipPds + { + public DateTime VersionUpdate; + public uint PrivateDataSpecifier; + public List PrivateDataSessions; + } public bool DvbNipPrivateDataSpecifier(NipActualCarrierInformation currentCarrierInformation, DateTime versionUpdate, uint privateDataSpecifier, List privateDataSessions) { - throw new NotImplementedException(); + NipPds incomingObject = new NipPds + { + VersionUpdate = versionUpdate, + PrivateDataSpecifier = privateDataSpecifier, + PrivateDataSessions = privateDataSessions + }; + string path = Path.Combine(rootDirectory.FullName, "DVB-NIP", "PDS", + currentCarrierInformation.NipNetworkId.ToString(), currentCarrierInformation.NipCarrierId.ToString(), + currentCarrierInformation.NipLinkId.ToString() + ".json"); + FileInfo fileInfo = new FileInfo(path); + if (fileInfo.Exists) + { + string oldJson = File.ReadAllText(fileInfo.FullName); + NipPds oldObject = JsonConvert.DeserializeObject(oldJson); + if (incomingObject.VersionUpdate < oldObject.VersionUpdate) + { + return false; + } + } + + string newJson = JsonConvert.SerializeObject(incomingObject); + File.WriteAllText(path, newJson); + return true; } public bool DvbNipTestForNetwork(BroadcastNetworkType network) { - throw new NotImplementedException(); + string path = Path.Combine(rootDirectory.FullName, "DVB-NIP", "networks", network.NIPNetworkID.ToString() + ".json"); + FileInfo fi = new FileInfo(path); + return fi.Exists; } public void DvbNipInsertNetwork(BroadcastNetworkType network) { - throw new NotImplementedException(); + string path = Path.Combine(rootDirectory.FullName, "DVB-NIP", "networks", network.NIPNetworkID.ToString() + ".json"); + FileInfo fi = new FileInfo(path); + fi.Directory.EnsureExists(); + string json = JsonConvert.SerializeObject(network); + File.WriteAllText(path, json); } public bool DvbNipTestForService(BroadcastMediaStreamType broadcastMediaStreamType) { - throw new NotImplementedException(); + string path = Path.Combine(rootDirectory.FullName, "DVB-NIP", "networks", + broadcastMediaStreamType.NIPNetworkID.ToString(), broadcastMediaStreamType.NIPCarrierID.ToString(), + broadcastMediaStreamType.NIPServiceID.ToString() + ".json"); + FileInfo fi = new FileInfo(path); + return fi.Exists; } public void DvbNipInsertService(BroadcastMediaStreamType broadcastMediaStreamType) { - throw new NotImplementedException(); + string path = Path.Combine(rootDirectory.FullName, "DVB-NIP", "networks", + broadcastMediaStreamType.NIPNetworkID.ToString(), broadcastMediaStreamType.NIPCarrierID.ToString(), + broadcastMediaStreamType.NIPServiceID.ToString() + ".json"); + FileInfo fi = new FileInfo(path); + fi.Directory.EnsureExists(); + string json = JsonConvert.SerializeObject(broadcastMediaStreamType); + File.WriteAllText(path, json); } public bool DvbNipTestForMulticastSession(MulticastSessionType multicastSession) @@ -1545,12 +1618,17 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem public bool DvbNipTestForCarrier(NipActualCarrierInformation currentCarrierInformation) { - throw new NotImplementedException(); + string path = Path.Combine(rootDirectory.FullName, "DVB-NIP", "carrier",currentCarrierInformation.NipNetworkId.ToString(), currentCarrierInformation.NipCarrierId.ToString(), currentCarrierInformation.NipLinkId.ToString(), currentCarrierInformation.NipServiceId.ToString() + ".txt"); + FileInfo fi = new FileInfo(path); + return fi.Exists; } public void DvbNipInsertCarrier(NipActualCarrierInformation currentCarrierInformation) { - throw new NotImplementedException(); + string path = Path.Combine(rootDirectory.FullName, "DVB-NIP", "carrier",currentCarrierInformation.NipNetworkId.ToString(), currentCarrierInformation.NipCarrierId.ToString(), currentCarrierInformation.NipLinkId.ToString(), currentCarrierInformation.NipServiceId.ToString() + ".txt"); + FileInfo fi = new FileInfo(path); + fi.Directory.EnsureExists(); + File.WriteAllText(path, currentCarrierInformation.NipStreamProviderName); } public DateTime GetLastDvbiServiceListEntryPointUpdateDate(long sourceHash) diff --git a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs index 22f3b41..d4c09f1 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs @@ -1702,7 +1702,19 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory public void UpdateDvbiService(DvbIService service) { - throw new NotImplementedException(); + if (_dvbiServices == null) + return; + + foreach (DvbIService oldService in _dvbiServices) + { + if (oldService.Id == service.Id) + { + _dvbiServices.Remove(oldService); + break; + } + } + + _dvbiServices.Add(service); } } } diff --git a/skyscraper8/bin/Debug/skyscraper5.ini b/skyscraper8/bin/Debug/skyscraper5.ini new file mode 100644 index 0000000..1233db7 --- /dev/null +++ b/skyscraper8/bin/Debug/skyscraper5.ini @@ -0,0 +1,22 @@ +[startup] +dataStorage=3 +objectStorage=1 + +[plugins_disabled] +postgresql=C:\Users\Sascha Schiemann\source\repos\skyscraper8\DataTableStorages\skyscraper5.Data.PostgreSql\bin\Debug\net8.0\skyscraper5.Data.PostgreSql.dll +minio=C:\Users\Sascha Schiemann\source\repos\skyscraper8\BlobStorages\skyscraper5.Data.Minio\bin\Debug\net8.0\skyscraper5.Data.Minio.dll +epgcollector=C:\Users\Sascha Schiemann\source\repos\skyscraper8\PrivateDataSpecifiers\skyscraper8.EPGCollectorPort\bin\Debug\net8.0\skyscraper8.EPGCollectorPort.dll + +[objectStorage1] +Bucket=skyscraper5 +Secure=0 +SecretKey=12345678 +AccessKey=feyris-tan +Endpoint=172.20.20.3:9000 + +[dataStorage3] +Username=ft +Port=5432 +Password=welcometotheworld +Host=172.20.20.17 +Database=skyscraper5 \ No newline at end of file