From 58e6dc00d2f5e868701d630cdd8c21ce3873646e Mon Sep 17 00:00:00 2001 From: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Tue, 3 Jun 2025 11:48:18 +0200 Subject: [PATCH] Additions for Astra's SGT. --- .gitignore | 1 + .../0x80_ArdVpsDescriptor.cs | 4 + .../AstraBarkerTransponderTests.cs | 45 +- .../DataBroadcasting/DataCarouselDecoder.cs | 4 + .../DataCarouselEventHandler.cs | 5 +- .../SkyscraperVfs/ObjectCarouselMetadata.cs | 51 +- .../Dvb/Descriptors/0x48_ServiceDescriptor.cs | 4 +- .../0x49_CountryAvailabilityDescriptor.cs | 4 +- .../0x53_CaIdentifierDescriptor.cs | 2 +- .../0x5F_PrivateDataSpecifierDescriptor.cs | 2 +- .../Dvb/UserDefinedDescriptorUnpacker.cs | 6 +- skyscraper8/DvbI/DvbIFilesystemProcessor.cs | 37 ++ skyscraper8/DvbI/DvbIUtils.cs | 28 ++ ...ep_app1_DVB-I_slep_app2_DVB-I_slep_app3.cs | 446 ++++++++++++++++++ skyscraper8/Properties/launchSettings.json | 2 +- .../0x88_ServiceListNameDescriptor.cs | 27 ++ .../Descriptors/0x93_BouquetListDescriptor.cs | 46 ++ .../0xD1_VirtualServiceIdDescriptor.cs | 31 ++ skyscraper8/Ses/SgtCandidate.cs | 48 ++ skyscraper8/Ses/SgtError.cs | 14 + skyscraper8/Ses/SgtEventHandler.cs | 15 + skyscraper8/Ses/SgtList.cs | 46 ++ skyscraper8/Ses/SgtParser.cs | 184 ++++++++ skyscraper8/Ses/SgtService.cs | 57 +++ .../Skyscraper/Plugins/PluginManager.cs | 28 ++ .../Skyscraper/Scraper/SkyscraperContext.cs | 45 +- .../Scraper/SkyscraperContextEvent.cs | 4 +- .../Filesystem/FilesystemScraperStorage.cs | 21 + .../Scraper/Storage/IScraperStorage.cs | 5 + .../InMemory/InMemoryScraperStorage.cs | 69 ++- .../InMemory/Model/DbBlindscanJobContainer.cs | 122 +++++ .../Scraper/Storage/Split/DataStorage.cs | 5 + .../Storage/Split/SplitScraperStorage.cs | 25 + .../Contestants/DataCarouselContestant.cs | 10 +- skyscraper8/skyscraper8.csproj | 4 + skyscraper8/yo3explorer/Filesystem.cs | 67 +++ .../yo3explorer/FilesystemProcessorPlugin.cs | 24 + skyscraper8/yo3explorer/yo3explorerState.cs | 26 + .../yo3explorerToSkyscraperContextBridge.cs | 12 + 39 files changed, 1551 insertions(+), 25 deletions(-) create mode 100644 skyscraper8/DvbI/DvbIFilesystemProcessor.cs create mode 100644 skyscraper8/DvbI/DvbIUtils.cs create mode 100644 skyscraper8/DvbI/Model/DVB-I_slep_DVB-I_slep_app1_DVB-I_slep_app2_DVB-I_slep_app3.cs create mode 100644 skyscraper8/Ses/Descriptors/0x88_ServiceListNameDescriptor.cs create mode 100644 skyscraper8/Ses/Descriptors/0x93_BouquetListDescriptor.cs create mode 100644 skyscraper8/Ses/Descriptors/0xD1_VirtualServiceIdDescriptor.cs create mode 100644 skyscraper8/Ses/SgtCandidate.cs create mode 100644 skyscraper8/Ses/SgtError.cs create mode 100644 skyscraper8/Ses/SgtEventHandler.cs create mode 100644 skyscraper8/Ses/SgtList.cs create mode 100644 skyscraper8/Ses/SgtParser.cs create mode 100644 skyscraper8/Ses/SgtService.cs create mode 100644 skyscraper8/Skyscraper/Scraper/Storage/InMemory/Model/DbBlindscanJobContainer.cs create mode 100644 skyscraper8/yo3explorer/Filesystem.cs create mode 100644 skyscraper8/yo3explorer/FilesystemProcessorPlugin.cs create mode 100644 skyscraper8/yo3explorer/yo3explorerState.cs create mode 100644 skyscraper8/yo3explorer/yo3explorerToSkyscraperContextBridge.cs diff --git a/.gitignore b/.gitignore index 5773706..a334d03 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,4 @@ imgui.ini /skyscraper8/obj /GUIs/skyscraper8.UI.ImGui/bin/Debug/net8.0/skyscraper5.ini /.vs/skyscraper8/CopilotIndices/17.14.698.11175 +/GUIs/skyscraper8.UI.ImGui/bin/Debug/net8.0 diff --git a/PrivateDataSpecifiers/skyscraper5.PrivateDataSpecifiers.ArdZdfOrf/0x80_ArdVpsDescriptor.cs b/PrivateDataSpecifiers/skyscraper5.PrivateDataSpecifiers.ArdZdfOrf/0x80_ArdVpsDescriptor.cs index e7bfa51..30cff96 100644 --- a/PrivateDataSpecifiers/skyscraper5.PrivateDataSpecifiers.ArdZdfOrf/0x80_ArdVpsDescriptor.cs +++ b/PrivateDataSpecifiers/skyscraper5.PrivateDataSpecifiers.ArdZdfOrf/0x80_ArdVpsDescriptor.cs @@ -18,9 +18,13 @@ namespace skyscraper5.Ard public ArdVpsDescriptor(byte[] buffer) { if (buffer.Length != 13) + { + Valid = false; return; + } VpsString = Encoding.UTF8.GetString(buffer); + Valid = true; } public string VpsString { get; private set; } diff --git a/skyscraper8.Tests/AstraBarkerTransponderTests.cs b/skyscraper8.Tests/AstraBarkerTransponderTests.cs index 9cadf09..9f12657 100644 --- a/skyscraper8.Tests/AstraBarkerTransponderTests.cs +++ b/skyscraper8.Tests/AstraBarkerTransponderTests.cs @@ -1,6 +1,7 @@ using skyscraper5.Mpeg2; using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants; +using skyscraper8.Ses; using skyscraper8.Tests.ClassDependencies.AsraBarkerTransponderTests; using System; using System.Collections.Generic; @@ -13,7 +14,7 @@ namespace skyscraper8.Tests { public class AstraBarkerTransponderTests { - private const string BARKER_TRANSPONDER_FILE_PATH = "Z:\\Freebies\\Datasets\\SkyscraperLibrarian\\DVB-S Mai 2025\\sgt-000000.ts"; + private const string BARKER_TRANSPONDER_FILE_PATH = "C:\\Temp\\Astra1_12604_v_SGT-000000.ts"; private Stream GetBarkerTransponder() { FileInfo fi = new FileInfo(BARKER_TRANSPONDER_FILE_PATH); @@ -39,7 +40,6 @@ namespace skyscraper8.Tests { descriptorUnpacker.SetUserDefined(i, true); } - descriptorUnpacker.SetUserDefined(0xfe, true); TsContext tsContext = new TsContext(); @@ -57,5 +57,46 @@ namespace skyscraper8.Tests } stream.Close(); } + + [Fact] + public void TestAstraLcn() + { + Stream stream = GetBarkerTransponder(); + if (stream == null) + return; + + SgtCandidate contestant = new SgtCandidate(0x0777); + SgtCandidate contestant2 = new SgtCandidate(0x0776); + + TsDescriptorUnpacker descriptorUnpacker = TsDescriptorUnpacker.GetInstance(); + for (byte i = 0x80; i < 0xfe; i++) + { + descriptorUnpacker.SetUserDefined(i, true); + } + descriptorUnpacker.SetUserDefined(0xfe, true); + + TsContext tsContext = new TsContext(); + tsContext.FilterChain = new List(); + tsContext.FilterChain.Add(new DummyFilter()); + tsContext.RegisterPacketProcessor(0x0777, contestant.PacketProcessor); + tsContext.RegisterPacketProcessor(0x0776, contestant2.PacketProcessor); + + byte[] buffer = new byte[188]; + while (stream.GetAvailableBytes() >= 188) + { + stream.Read(buffer, 0, 188); + tsContext.PushPacket(buffer); + bool winnerA = contestant.Score >= 10; + bool winnerB = contestant2.Score >= 10; + if (winnerA) + { + if (winnerB) + { + return; + } + } + } + stream.Close(); + } } } diff --git a/skyscraper8/Dvb/DataBroadcasting/DataCarouselDecoder.cs b/skyscraper8/Dvb/DataBroadcasting/DataCarouselDecoder.cs index 5351e84..3ea34de 100644 --- a/skyscraper8/Dvb/DataBroadcasting/DataCarouselDecoder.cs +++ b/skyscraper8/Dvb/DataBroadcasting/DataCarouselDecoder.cs @@ -16,6 +16,7 @@ using skyscraper5.Mpeg2.Psi.Model; using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.Scraper; using skyscraper5.Skyscraper.Scraper.Utils; +using Tsubasa.IO; namespace skyscraper5.Dvb.DataBroadcasting { @@ -210,7 +211,10 @@ namespace skyscraper5.Dvb.DataBroadcasting vfs.DirectoriesCreated = 0; ObjectCarouselUtilities.ExtractBiopModule(module, assembledStream, vfs); if (vfs.DirectoriesCreated != 0) + { eventHandler.PreventDsmCcModuleRepetition(programMappingStream.ElementaryPid, module.ModuleId, module.ModuleVersion); + eventHandler.ProcessVirtualFilesystem((IFilesystem)vfs, programMappingStream); + } return; } eventHandler.NotifyDownloadComplete(programMappingStream.ElementaryPid, module.ModuleId, module.ModuleVersion, assembledStream, isObjectCarousel); diff --git a/skyscraper8/Dvb/DataBroadcasting/DataCarouselEventHandler.cs b/skyscraper8/Dvb/DataBroadcasting/DataCarouselEventHandler.cs index 7a0dc53..5d21d3c 100644 --- a/skyscraper8/Dvb/DataBroadcasting/DataCarouselEventHandler.cs +++ b/skyscraper8/Dvb/DataBroadcasting/DataCarouselEventHandler.cs @@ -6,7 +6,9 @@ using System.Text; using System.Threading.Tasks; using skyscraper5.DsmCc.Descriptors; using skyscraper5.DsmCc.Message; +using skyscraper5.Dvb.DataBroadcasting.Biop; using skyscraper5.Mpeg2.Psi.Model; +using Tsubasa.IO; namespace skyscraper5.Dvb.DataBroadcasting { @@ -19,5 +21,6 @@ namespace skyscraper5.Dvb.DataBroadcasting void NotifyDownloadComplete(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion, Stream result, bool isObjectCarousel); void DsmCcDoItNowEvent(ProgramMapping programMapping, StreamEventDescriptor descriptorListStreamEventDescriptor, int sourcePid); void PreventDsmCcModuleRepetition(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion); - } + void ProcessVirtualFilesystem(IFilesystem vfs, ProgramMappingStream programMappingStream); + } } diff --git a/skyscraper8/Dvb/DataBroadcasting/SkyscraperVfs/ObjectCarouselMetadata.cs b/skyscraper8/Dvb/DataBroadcasting/SkyscraperVfs/ObjectCarouselMetadata.cs index 77f0ba4..0d3e887 100644 --- a/skyscraper8/Dvb/DataBroadcasting/SkyscraperVfs/ObjectCarouselMetadata.cs +++ b/skyscraper8/Dvb/DataBroadcasting/SkyscraperVfs/ObjectCarouselMetadata.cs @@ -4,10 +4,11 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using skyscraper5.Mpeg2.Psi.Model; +using Tsubasa.IO; namespace skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs { - class ObjectCarouselMetadata + class ObjectCarouselMetadata : IFilesystem { public ObjectCarouselMetadata(ObjectCarouselEventHandler eventHandler, int sourcePid, ProgramMapping programMapping) { @@ -28,5 +29,53 @@ namespace skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs public ProgramMapping ProgramMapping { get; private set; } public int LastExtractions { get; set; } public int DirectoriesCreated { get; set; } + + #region yo3explorer Driver + private string[] _wrappedFileList; + public string[] FileList + { + get + { + if (_wrappedFileList == null) + { + _wrappedFileList = vfsFiles.Select(x => x.ToString()).ToArray(); + } + return _wrappedFileList; + } + } + + public string FilesystemName + { + get + { + return string.Format("DSM-CC Object Carousel;{0};", SourcePid); + } + } + + public bool FileExists(string filename) + { + foreach (VfsFile file in vfsFiles) + { + if (file.ToString().Equals(filename)) + return true; + } + return false; + } + + public byte[] GetFile(string filename) + { + foreach (VfsFile file in vfsFiles) + { + if (file.ToString().Equals(filename)) + return file.FileContent; + } + throw new FileNotFoundException(filename); + } + + public void Dispose() + { + + } + #endregion } } diff --git a/skyscraper8/Dvb/Descriptors/0x48_ServiceDescriptor.cs b/skyscraper8/Dvb/Descriptors/0x48_ServiceDescriptor.cs index 2140ebf..7ca962b 100644 --- a/skyscraper8/Dvb/Descriptors/0x48_ServiceDescriptor.cs +++ b/skyscraper8/Dvb/Descriptors/0x48_ServiceDescriptor.cs @@ -12,7 +12,7 @@ using skyscraper5.Skyscraper.Text; namespace skyscraper5.Dvb.Descriptors { [SkyscraperPlugin] - [TsDescriptor(0x48,"SDT")] + [TsDescriptor(0x48,"SDT","Astra SGT")] [BannedTable("TSDT","PMT")] public class ServiceDescriptor : TsDescriptor { @@ -68,6 +68,8 @@ namespace skyscraper5.Dvb.Descriptors H264StereoscopicHdNvodRefence = 0x1e, TV_HEVC = 0x1f, _4KTV_HEVC = 0x20, + VVC = 0x21, + AVS3 = 0x22 } public override byte[] Serialize() diff --git a/skyscraper8/Dvb/Descriptors/0x49_CountryAvailabilityDescriptor.cs b/skyscraper8/Dvb/Descriptors/0x49_CountryAvailabilityDescriptor.cs index fca12c0..681a1d4 100644 --- a/skyscraper8/Dvb/Descriptors/0x49_CountryAvailabilityDescriptor.cs +++ b/skyscraper8/Dvb/Descriptors/0x49_CountryAvailabilityDescriptor.cs @@ -10,9 +10,9 @@ using skyscraper5.Skyscraper.Plugins; namespace skyscraper5.Dvb.Descriptors { [SkyscraperPlugin] - [TsDescriptor(0x49,"BAT","SDT")] + [TsDescriptor(0x49,"BAT","SDT","Astra SGT")] [BannedTable("PMT","TSDT")] - class CountryAvailabilityDescriptor : TsDescriptor + public class CountryAvailabilityDescriptor : TsDescriptor { public CountryAvailabilityDescriptor(byte[] buffer) { diff --git a/skyscraper8/Dvb/Descriptors/0x53_CaIdentifierDescriptor.cs b/skyscraper8/Dvb/Descriptors/0x53_CaIdentifierDescriptor.cs index 746f1b5..4eb1e21 100644 --- a/skyscraper8/Dvb/Descriptors/0x53_CaIdentifierDescriptor.cs +++ b/skyscraper8/Dvb/Descriptors/0x53_CaIdentifierDescriptor.cs @@ -11,7 +11,7 @@ using skyscraper5.Skyscraper.Plugins; namespace skyscraper5.Dvb.Descriptors { [SkyscraperPlugin] - [TsDescriptor(0x53,"BAT","SDT","EIT")] + [TsDescriptor(0x53,"BAT","SDT","EIT","Astra SGT")] [BannedTable("TSDT")] class CaIdentifierDescriptor : TsDescriptor { diff --git a/skyscraper8/Dvb/Descriptors/0x5F_PrivateDataSpecifierDescriptor.cs b/skyscraper8/Dvb/Descriptors/0x5F_PrivateDataSpecifierDescriptor.cs index c8b4b7f..016e280 100644 --- a/skyscraper8/Dvb/Descriptors/0x5F_PrivateDataSpecifierDescriptor.cs +++ b/skyscraper8/Dvb/Descriptors/0x5F_PrivateDataSpecifierDescriptor.cs @@ -9,7 +9,7 @@ using skyscraper5.Skyscraper.Plugins; namespace skyscraper5.Dvb.Descriptors { [SkyscraperPlugin] - [TsDescriptor(0x5f,"NIT","BAT","SDT","EIT","PMT")] + [TsDescriptor(0x5f,"NIT","BAT","SDT","EIT","PMT", "Astra SGT")] [BannedTable("CAT")] // <-- Scientific Atlanta is known to put private_data_specifier_descriptors into the CAT, however this is a private extension. public class PrivateDataSpecifierDescriptor : TsDescriptor { diff --git a/skyscraper8/Dvb/UserDefinedDescriptorUnpacker.cs b/skyscraper8/Dvb/UserDefinedDescriptorUnpacker.cs index 94eec68..89add61 100644 --- a/skyscraper8/Dvb/UserDefinedDescriptorUnpacker.cs +++ b/skyscraper8/Dvb/UserDefinedDescriptorUnpacker.cs @@ -49,7 +49,7 @@ namespace skyscraper5.Dvb private IReadOnlyDictionary constructors; - public TsDescriptor UnpackUserDefinedDescriptor(UserDefinedDescriptor userDefinedDescriptor, uint privateDataSpecifier, string lookupTable) + public TsDescriptor UnpackUserDefinedDescriptor(UserDefinedDescriptor userDefinedDescriptor, uint privateDataSpecifier, string lookupTable, bool crashOnMissingDescriptor = false) { if (constructors == null) constructors = PluginManager.GetInstance().GetUserDefinedDescriptors(); @@ -69,6 +69,10 @@ namespace skyscraper5.Dvb return (TsDescriptor)constructorInfo.Invoke(new object[] { userDefinedDescriptor.Data }); } WarnMissingDescriptor(userDefinedDescriptor.DescriptorTag, privateDataSpecifier); + if (crashOnMissingDescriptor) + { + throw new NotImplementedException(String.Format("Missing Descriptor 0x{0:X2} from private data specifier 0x{1:X8} in {2}", userDefinedDescriptor.DescriptorTag, privateDataSpecifier, lookupTable)); + } return null; } diff --git a/skyscraper8/DvbI/DvbIFilesystemProcessor.cs b/skyscraper8/DvbI/DvbIFilesystemProcessor.cs new file mode 100644 index 0000000..4215758 --- /dev/null +++ b/skyscraper8/DvbI/DvbIFilesystemProcessor.cs @@ -0,0 +1,37 @@ +using skyscraper5.Skyscraper.Plugins; +using skyscraper8.yo3explorer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; +using Tsubasa.IO; +using moe.yo3explorer.skyscraper8.DVBI.Model; + +namespace skyscraper8.DvbI +{ + /// + /// See https://www.tara-systems.de/wp-content/uploads/2024/08/DVB-I_Instant_Channel_List_Setup_IBC2024.pdf + /// There is no official specification for this. + /// This is a best guess reverse engineering of the DVB-I link found on 12,604/H on Astra 19,2° + /// + [SkyscraperPlugin] + internal class DvbIFilesystemProcessor : FilesystemProcessorPlugin + { + private const string INDEX_FILENAME = "\\DVB-I_slep.xml"; + + private XmlSerializer serviceListEntryPointSerializer; + + public void ProcessFilesystem(IFilesystem vfs, yo3explorerToSkyscraperContextBridge context, yo3explorerState state) + { + if (!vfs.FileExists(INDEX_FILENAME)) + return; + + byte[] slepBytes = vfs.GetFile(INDEX_FILENAME); + ServiceListEntryPoints serviceListEntryPoints = DvbIUtils.UnpackServiceListEntryPoints(slepBytes); + + throw new NotImplementedException(); + } + } +} diff --git a/skyscraper8/DvbI/DvbIUtils.cs b/skyscraper8/DvbI/DvbIUtils.cs new file mode 100644 index 0000000..006b25b --- /dev/null +++ b/skyscraper8/DvbI/DvbIUtils.cs @@ -0,0 +1,28 @@ +using moe.yo3explorer.skyscraper8.DVBI.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace skyscraper8.DvbI +{ + internal class DvbIUtils + { + private DvbIUtils() { } + + private static XmlSerializer serviceListEntryPointSerializer; + + public static ServiceListEntryPoints UnpackServiceListEntryPoints(byte[] buffer) + { + if (serviceListEntryPointSerializer == null) + serviceListEntryPointSerializer = new XmlSerializer(typeof(ServiceListEntryPoints)); + + MemoryStream slepStream = new MemoryStream(buffer, false); + object slepWrapped = serviceListEntryPointSerializer.Deserialize(slepStream); + ServiceListEntryPoints serviceListEntryPoint = (ServiceListEntryPoints)slepWrapped; + return serviceListEntryPoint; + } + } +} diff --git a/skyscraper8/DvbI/Model/DVB-I_slep_DVB-I_slep_app1_DVB-I_slep_app2_DVB-I_slep_app3.cs b/skyscraper8/DvbI/Model/DVB-I_slep_DVB-I_slep_app1_DVB-I_slep_app2_DVB-I_slep_app3.cs new file mode 100644 index 0000000..dc61f32 --- /dev/null +++ b/skyscraper8/DvbI/Model/DVB-I_slep_DVB-I_slep_app1_DVB-I_slep_app2_DVB-I_slep_app3.cs @@ -0,0 +1,446 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// +// This source code was auto-generated by xsd, Version=4.8.9037.0. +// +namespace moe.yo3explorer.skyscraper8.DVBI.Model { + using System.Xml.Serialization; + + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="urn:dvb:metadata:servicelistdiscovery:2024", IsNullable=false)] + public partial class ServiceListEntryPoints { + + private ServiceListEntryPointsServiceListRegistryEntity[] serviceListRegistryEntityField; + + private ServiceListEntryPointsProviderOffering[] providerOfferingField; + + private string langField; + + /// + [System.Xml.Serialization.XmlElementAttribute("ServiceListRegistryEntity")] + public ServiceListEntryPointsServiceListRegistryEntity[] ServiceListRegistryEntity { + get { + return this.serviceListRegistryEntityField; + } + set { + this.serviceListRegistryEntityField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ProviderOffering")] + public ServiceListEntryPointsProviderOffering[] ProviderOffering { + get { + return this.providerOfferingField; + } + set { + this.providerOfferingField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, Namespace="http://www.w3.org/XML/1998/namespace")] + public string lang { + get { + return this.langField; + } + set { + this.langField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + public partial class ServiceListEntryPointsServiceListRegistryEntity { + + private string nameField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + public partial class ServiceListEntryPointsProviderOffering { + + private ServiceListEntryPointsProviderOfferingProvider[] providerField; + + private ServiceListEntryPointsProviderOfferingServiceListOffering[] serviceListOfferingField; + + /// + [System.Xml.Serialization.XmlElementAttribute("Provider")] + public ServiceListEntryPointsProviderOfferingProvider[] Provider { + get { + return this.providerField; + } + set { + this.providerField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ServiceListOffering")] + public ServiceListEntryPointsProviderOfferingServiceListOffering[] ServiceListOffering { + get { + return this.serviceListOfferingField; + } + set { + this.serviceListOfferingField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + public partial class ServiceListEntryPointsProviderOfferingProvider { + + private string nameField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + public partial class ServiceListEntryPointsProviderOfferingServiceListOffering { + + private string serviceListNameField; + + private string serviceListIdField; + + private ServiceListEntryPointsProviderOfferingServiceListOfferingServiceListURI[] serviceListURIField; + + private ServiceListEntryPointsProviderOfferingServiceListOfferingDelivery[] deliveryField; + + private RelatedMaterial relatedMaterialField; + + /// + public string ServiceListName { + get { + return this.serviceListNameField; + } + set { + this.serviceListNameField = value; + } + } + + /// + public string ServiceListId { + get { + return this.serviceListIdField; + } + set { + this.serviceListIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ServiceListURI")] + public ServiceListEntryPointsProviderOfferingServiceListOfferingServiceListURI[] ServiceListURI { + get { + return this.serviceListURIField; + } + set { + this.serviceListURIField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Delivery")] + public ServiceListEntryPointsProviderOfferingServiceListOfferingDelivery[] Delivery { + get { + return this.deliveryField; + } + set { + this.deliveryField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:dvb:metadata:servicediscovery-types:2023")] + public RelatedMaterial RelatedMaterial { + get { + return this.relatedMaterialField; + } + set { + this.relatedMaterialField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + public partial class ServiceListEntryPointsProviderOfferingServiceListOfferingServiceListURI { + + private string uRIField; + + private string contentTypeField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:dvb:metadata:servicediscovery-types:2023")] + public string URI { + get { + return this.uRIField; + } + set { + this.uRIField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string contentType { + get { + return this.contentTypeField; + } + set { + this.contentTypeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + public partial class ServiceListEntryPointsProviderOfferingServiceListOfferingDelivery { + + private string dASHDeliveryField; + + private ServiceListEntryPointsProviderOfferingServiceListOfferingDeliveryDVBSDelivery[] dVBSDeliveryField; + + /// + public string DASHDelivery { + get { + return this.dASHDeliveryField; + } + set { + this.dASHDeliveryField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("DVBSDelivery")] + public ServiceListEntryPointsProviderOfferingServiceListOfferingDeliveryDVBSDelivery[] DVBSDelivery { + get { + return this.dVBSDeliveryField; + } + set { + this.dVBSDeliveryField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + public partial class ServiceListEntryPointsProviderOfferingServiceListOfferingDeliveryDVBSDelivery { + + private string orbitalPositionField; + + /// + public string OrbitalPosition { + get { + return this.orbitalPositionField; + } + set { + this.orbitalPositionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicediscovery-types:2023")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="urn:dvb:metadata:servicediscovery-types:2023", IsNullable=false)] + public partial class RelatedMaterial { + + private HowRelated howRelatedField; + + private MediaLocatorMediaUri[] mediaLocatorField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:tva:metadata:2024")] + public HowRelated HowRelated { + get { + return this.howRelatedField; + } + set { + this.howRelatedField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayAttribute(Namespace="urn:tva:metadata:2024")] + [System.Xml.Serialization.XmlArrayItemAttribute("MediaUri")] + public MediaLocatorMediaUri[] MediaLocator { + get { + return this.mediaLocatorField; + } + set { + this.mediaLocatorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:tva:metadata:2024")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="urn:tva:metadata:2024", IsNullable=false)] + public partial class HowRelated { + + private string hrefField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string href { + get { + return this.hrefField; + } + set { + this.hrefField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:tva:metadata:2024")] + public partial class MediaLocatorMediaUri { + + private string contentTypeField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string contentType { + get { + return this.contentTypeField; + } + set { + this.contentTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:dvb:metadata:servicelistdiscovery:2024")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="urn:dvb:metadata:servicelistdiscovery:2024", IsNullable=false)] + public partial class NewDataSet { + + private ServiceListEntryPoints[] itemsField; + + /// + [System.Xml.Serialization.XmlElementAttribute("ServiceListEntryPoints")] + public ServiceListEntryPoints[] Items { + get { + return this.itemsField; + } + set { + this.itemsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:tva:metadata:2024")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="urn:tva:metadata:2024", IsNullable=false)] + public partial class MediaLocator { + + private MediaLocatorMediaUri[] mediaUriField; + + /// + [System.Xml.Serialization.XmlElementAttribute("MediaUri", IsNullable=true)] + public MediaLocatorMediaUri[] MediaUri { + get { + return this.mediaUriField; + } + set { + this.mediaUriField = value; + } + } + } +} diff --git a/skyscraper8/Properties/launchSettings.json b/skyscraper8/Properties/launchSettings.json index 9a9887f..0549299 100644 --- a/skyscraper8/Properties/launchSettings.json +++ b/skyscraper8/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "skyscraper8": { "commandName": "Project", - "commandLineArgs": "\"Z:\\Freebies\\Datasets\\SkyscraperLibrarian\\DVB-S Mai 2025\\sgt-000000.ts\"", + "commandLineArgs": "\"C:\\Temp\\Astra1_12604_v_SGT-000000.ts\"", "remoteDebugEnabled": false }, "Container (Dockerfile)": { diff --git a/skyscraper8/Ses/Descriptors/0x88_ServiceListNameDescriptor.cs b/skyscraper8/Ses/Descriptors/0x88_ServiceListNameDescriptor.cs new file mode 100644 index 0000000..33c64dc --- /dev/null +++ b/skyscraper8/Ses/Descriptors/0x88_ServiceListNameDescriptor.cs @@ -0,0 +1,27 @@ +using skyscraper5.Dvb; +using skyscraper5.Mpeg2; +using skyscraper5.Skyscraper.Plugins; +using skyscraper5.Skyscraper.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ses.Descriptors +{ + [SkyscraperPlugin] + [UserDefinedDescriptor(0x01, 0x88, "Astra SGT")] + internal class _0x88_ServiceListNameDescriptor : TsDescriptor + { + public _0x88_ServiceListNameDescriptor(byte[] buffer) + { + LanguageCode = Encoding.ASCII.GetString(buffer, 0, 3); + TextualDescription = En300468AnnexATextDecoder.GetInstance().Decode(buffer, 3, buffer.Length - 3); + Valid = true; + } + + public string LanguageCode { get; } + public string TextualDescription { get; } + } +} diff --git a/skyscraper8/Ses/Descriptors/0x93_BouquetListDescriptor.cs b/skyscraper8/Ses/Descriptors/0x93_BouquetListDescriptor.cs new file mode 100644 index 0000000..7891f8a --- /dev/null +++ b/skyscraper8/Ses/Descriptors/0x93_BouquetListDescriptor.cs @@ -0,0 +1,46 @@ +using skyscraper5.Dvb; +using skyscraper5.Mpeg2; +using skyscraper5.Skyscraper.IO; +using skyscraper5.Skyscraper.Plugins; +using skyscraper5.Skyscraper.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ses.Descriptors +{ + [SkyscraperPlugin] + [UserDefinedDescriptor(0x01, 0x93, "Astra SGT")] + internal class _0x93_BouquetListDescriptor : TsDescriptor + { + public _0x93_BouquetListDescriptor(byte[] buffer) + { + MemoryStream ms = new MemoryStream(buffer, false); + while (ms.GetAvailableBytes() >= 1) + { + byte bouquetNameLength = ms.ReadUInt8(); + if (bouquetNameLength != 0) + { + byte[] chars = ms.ReadBytes(bouquetNameLength); + string chars2 = En300468AnnexATextDecoder.GetInstance().Decode(chars); + if (!string.IsNullOrEmpty(chars2)) + { + if (string.IsNullOrEmpty(Name)) + { + Name = chars2; + } + else + { + throw new NotImplementedException("multiple bouquet names"); + } + } + } + } + Valid = true; + } + + public string Name { get; private set; } + } +} diff --git a/skyscraper8/Ses/Descriptors/0xD1_VirtualServiceIdDescriptor.cs b/skyscraper8/Ses/Descriptors/0xD1_VirtualServiceIdDescriptor.cs new file mode 100644 index 0000000..69ad6f2 --- /dev/null +++ b/skyscraper8/Ses/Descriptors/0xD1_VirtualServiceIdDescriptor.cs @@ -0,0 +1,31 @@ +using skyscraper5.Dvb; +using skyscraper5.Mpeg2; +using skyscraper5.Skyscraper.Plugins; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ses.Descriptors +{ + [SkyscraperPlugin] + [UserDefinedDescriptor(0x01, 0xD1, "Astra SGT")] + internal class _0xD1_VirtualServiceIdDescriptor : TsDescriptor + { + public _0xD1_VirtualServiceIdDescriptor(byte[] buffer) + { + if (buffer.Length < 2) + { + Valid = false; + return; + } + + (buffer[1], buffer[0]) = (buffer[0], buffer[1]); + VirtualServiceId = BitConverter.ToUInt16(buffer, 0); + Valid = true; + } + + public ushort VirtualServiceId { get; } + } +} diff --git a/skyscraper8/Ses/SgtCandidate.cs b/skyscraper8/Ses/SgtCandidate.cs new file mode 100644 index 0000000..f530edc --- /dev/null +++ b/skyscraper8/Ses/SgtCandidate.cs @@ -0,0 +1,48 @@ +using skyscraper5.Mhp.Si; +using skyscraper5.Mpeg2; +using skyscraper5.Skyscraper.Plugins; +using skyscraper5.Skyscraper.Scraper; +using skyscraper5.Skyscraper.Scraper.StreamAutodetection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ses +{ + [SkyscraperPlugin] + public class SgtCandidate : Contestant, SgtEventHandler, IDisposable + { + public SgtCandidate(int pid) + : base("Asta SGT",pid) + { + PacketProcessor = new PsiDecoder(pid, new SgtParser(this)); + } + + public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext) + { + skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new SgtParser(skyscraperContext))); + } + + public override void Dispose() + { + } + + void SgtEventHandler.AnnounceSgtList(SgtList list) + { + if (list.CountryAvailabilities.Count > 0 || list.Names != null || list.PrivateDataSpecifier != 0x01) + Score++; + } + + void SgtEventHandler.OnSgtError(SgtError invalidTableId) + { + Score--; + } + + void SgtEventHandler.OnSgtService(SgtService child) + { + Score++; + } + } +} diff --git a/skyscraper8/Ses/SgtError.cs b/skyscraper8/Ses/SgtError.cs new file mode 100644 index 0000000..eb7700e --- /dev/null +++ b/skyscraper8/Ses/SgtError.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ses +{ + internal enum SgtError + { + InvalidTableId, + NoSectionSyntax + } +} diff --git a/skyscraper8/Ses/SgtEventHandler.cs b/skyscraper8/Ses/SgtEventHandler.cs new file mode 100644 index 0000000..e964629 --- /dev/null +++ b/skyscraper8/Ses/SgtEventHandler.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ses +{ + internal interface SgtEventHandler + { + void AnnounceSgtList(SgtList list); + void OnSgtError(SgtError invalidTableId); + void OnSgtService(SgtService child); + } +} diff --git a/skyscraper8/Ses/SgtList.cs b/skyscraper8/Ses/SgtList.cs new file mode 100644 index 0000000..2bd421c --- /dev/null +++ b/skyscraper8/Ses/SgtList.cs @@ -0,0 +1,46 @@ +using skyscraper5.Dvb.Descriptors; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ses +{ + public class SgtList + { + public SgtList(ushort serviceListId, uint v) + { + ServiceListId = serviceListId; + PrivateDataSpecifier = v; + CountryAvailabilities = new Dictionary(); + } + + public ushort ServiceListId { get; } + public uint PrivateDataSpecifier { get; internal set; } + + public Dictionary Names { get; internal set; } + public Dictionary CountryAvailabilities { get; internal set; } + + public string GetName() + { + if (Names == null) + return "???"; + + if (Names.Count == 0) + return "???"; + + foreach (KeyValuePair name in Names) + { + if (!string.IsNullOrEmpty(name.Value)) + { + return name.Value; + } + } + return "???"; + { + + } + } + } +} diff --git a/skyscraper8/Ses/SgtParser.cs b/skyscraper8/Ses/SgtParser.cs new file mode 100644 index 0000000..e303aef --- /dev/null +++ b/skyscraper8/Ses/SgtParser.cs @@ -0,0 +1,184 @@ +using skyscraper5.Dvb; +using skyscraper5.Dvb.Descriptors; +using skyscraper5.Mpeg2; +using skyscraper5.Mpeg2.Descriptors; +using skyscraper5.Skyscraper.IO; +using skyscraper8.Ses.Descriptors; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static skyscraper5.Dvb.Descriptors.ContentIdentifierDescriptor; + +namespace skyscraper8.Ses +{ + internal class SgtParser : IPsiProcessor + { + public SgtParser(SgtEventHandler eventHandler) + { + this.EventHandler = eventHandler; + } + + public SgtEventHandler EventHandler { get; } + + public void GatherPsi(PsiSection section, int sourcePid) + { + byte[] buffer = section.GetData(); + MemoryStream ms = new MemoryStream(buffer, false); + + byte table_id = ms.ReadUInt8(); + if (table_id != 0x91) + { + EventHandler.OnSgtError(SgtError.InvalidTableId); + return; + } + + byte byteA = ms.ReadUInt8(); + bool sectionSyntaxIndicator = (byteA & 0x80) != 0; + if (!sectionSyntaxIndicator) + { + EventHandler.OnSgtError(SgtError.NoSectionSyntax); + return; + } + bool reservedFutureUse = (byteA & 0x40) != 0; + int reserved = (byteA & 0x30) >> 4; + int sectionLength = (byteA & 0x0f); + sectionLength <<= 4; + sectionLength += ms.ReadUInt8(); + + ushort serviceListId = ms.ReadUInt16BE(); + + byte byteB = ms.ReadUInt8(); + int reservedB = (byteA & 0xc0) >> 6; + int versionNumber = (byteA & 0x3e) >> 1; + bool currentNextIndicator = (byteB & 0x01) != 0; + + byte sectionNumber = ms.ReadUInt8(); + byte lastSectionNumber = ms.ReadUInt8(); + ushort ReservedC = ms.ReadUInt16BE(); + + ushort uint16 = ms.ReadUInt16BE(); + int reservedFutureUseB = (uint16 & 0xf000) >> 12; + int serviceListDescriptorsLength = (uint16 & 0x0fff); + byte[] descriptorBuffer = ms.ReadBytes(serviceListDescriptorsLength); + IEnumerable descriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(descriptorBuffer, "Astra SGT"); + + SgtList list = new SgtList(serviceListId, 0x01); + + foreach (TsDescriptor rawDescriptor in descriptors) + { + switch (rawDescriptor.GetType().Name) + { + case nameof(PrivateDataSpecifierDescriptor): + PrivateDataSpecifierDescriptor pdsd = (PrivateDataSpecifierDescriptor)rawDescriptor; + list.PrivateDataSpecifier = pdsd.PrivateDataSpecifier; + break; + case nameof(UserDefinedDescriptor): + TsDescriptor userDefinedDescriptor = UserDefinedDescriptorUnpacker.GetInstance().UnpackUserDefinedDescriptor((UserDefinedDescriptor)rawDescriptor, list.PrivateDataSpecifier, "Astra SGT", true); + switch (userDefinedDescriptor.GetType().Name) + { + case nameof(_0x88_ServiceListNameDescriptor): + _0x88_ServiceListNameDescriptor slnd = (_0x88_ServiceListNameDescriptor)userDefinedDescriptor; + if (list.Names == null) + list.Names = new Dictionary(); + list.Names.Add(slnd.LanguageCode, slnd.TextualDescription); + break; + default: + throw new NotImplementedException(rawDescriptor.GetType().Name); + } + continue; + case nameof(CountryAvailabilityDescriptor): + CountryAvailabilityDescriptor cad = (CountryAvailabilityDescriptor)rawDescriptor; + foreach(string countryFlag in cad.CountryCodes) + { + list.CountryAvailabilities.Add(countryFlag, cad.CountryAvailabilityFlag); + } + break; + default: + throw new NotImplementedException(rawDescriptor.GetType().Name); + } + } + EventHandler.AnnounceSgtList(list); + + ushort uint16b = ms.ReadUInt16BE(); + int reservedFutureUseC = (uint16b & 0xf000) >> 12; + int serviceLoopLength = (uint16b & 0x0fff); + byte[] serviceLoopBuffer = ms.ReadBytes(serviceLoopLength); + ParseServiceLoop(serviceListId, serviceLoopBuffer,list.PrivateDataSpecifier); + + uint crc32 = ms.ReadUInt32BE(); + } + + private void ParseServiceLoop(ushort serviceListId, byte[] serviceLoopBuffer, uint? privateDataSpecifier) + { + MemoryStream ms = new MemoryStream(serviceLoopBuffer, false); + while (ms.GetAvailableBytes() > 6) + { + SgtService child = new SgtService(serviceListId); + child.ServiceId = ms.ReadUInt16BE(); + child.TransportStreamId = ms.ReadUInt16BE(); + child.OriginalNetworkId = ms.ReadUInt16BE(); + + ushort ushortA = ms.ReadUInt16BE(); + child.Lcn = (ushortA & 0xfc) >> 2; + child.VisibleServiceFlag = (ushortA & 0x02) != 0; + child.NewServiceFlag = (ushortA & 0x01) != 0; + child.GenreCode = ms.ReadUInt16BE(); + + ushort ushortB = ms.ReadUInt16BE(); + int reservedFutureUseB = (ushortB & 0xf000) >> 12; + int serviceListDescriptorsLength = (ushortB & 0x0fff); + byte[] descriptorBuffer = ms.ReadBytes(serviceListDescriptorsLength); + IEnumerable descriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(descriptorBuffer, "Astra SGT"); + child.PrivateDataSpecifier = privateDataSpecifier != null ? privateDataSpecifier.Value : 0x01; + foreach (TsDescriptor rawDescriptor in descriptors) + { + switch (rawDescriptor.GetType().Name) + { + case nameof(CaIdentifierDescriptor): + CaIdentifierDescriptor cid = (CaIdentifierDescriptor)rawDescriptor; + if (child.CaSystemIds != null) + throw new NotImplementedException("Multiple CA Identifier descriptors"); + child.CaSystemIds = cid.CaSystemIds; + continue; + case nameof(ServiceDescriptor): + ServiceDescriptor sd = (ServiceDescriptor)rawDescriptor; + if (child.ServiceDescriptor != null) + throw new NotImplementedException("Multiple Service descriptors"); + child.ServiceDescriptor = sd; + continue; + case nameof(UserDefinedDescriptor): + TsDescriptor userDefinedDescriptor = UserDefinedDescriptorUnpacker.GetInstance().UnpackUserDefinedDescriptor((UserDefinedDescriptor)rawDescriptor, child.PrivateDataSpecifier, "Astra SGT", true); + switch(userDefinedDescriptor.GetType().Name) + { + case nameof(_0xD1_VirtualServiceIdDescriptor): + _0xD1_VirtualServiceIdDescriptor vsid = (_0xD1_VirtualServiceIdDescriptor)userDefinedDescriptor; + if (child.VirtualServiceIds == null) + child.VirtualServiceIds = new List(); + child.VirtualServiceIds.Add(vsid.VirtualServiceId); + continue; + case nameof(_0x93_BouquetListDescriptor): + _0x93_BouquetListDescriptor bld = (_0x93_BouquetListDescriptor)userDefinedDescriptor; + if (!string.IsNullOrEmpty(child.BouquetList)) + throw new NotImplementedException("Multiple bouquets in child."); + child.BouquetList = bld.Name; + continue; + default: + throw new NotImplementedException(rawDescriptor.GetType().Name); + } + continue; + case nameof(PrivateDataSpecifierDescriptor): + PrivateDataSpecifierDescriptor pds = (PrivateDataSpecifierDescriptor)rawDescriptor; + if (pds.PrivateDataSpecifier != child.PrivateDataSpecifier) + throw new NotImplementedException("Multiple private data specifiers?"); + continue; + default: + throw new NotImplementedException(rawDescriptor.GetType().Name); + } + } + EventHandler.OnSgtService(child); + } + } + } +} diff --git a/skyscraper8/Ses/SgtService.cs b/skyscraper8/Ses/SgtService.cs new file mode 100644 index 0000000..c752725 --- /dev/null +++ b/skyscraper8/Ses/SgtService.cs @@ -0,0 +1,57 @@ +using skyscraper5.Dvb.Descriptors; +using skyscraper8.Ses.Descriptors; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ses +{ + public class SgtService + { + public SgtService(ushort serviceListId) + { + ServiceListId = serviceListId; + } + + public ushort ServiceListId { get; } + + public ushort ServiceId { get; internal set; } + public ushort TransportStreamId { get; internal set; } + public ushort OriginalNetworkId { get; internal set; } + public int Lcn { get; internal set; } + public bool VisibleServiceFlag { get; internal set; } + public bool NewServiceFlag { get; internal set; } + public ushort GenreCode { get; internal set; } + + //In SGT this is mandatory and defaults to 0x01 + public uint PrivateDataSpecifier { get; internal set; } + public ushort[] CaSystemIds { get; internal set; } + public ServiceDescriptor ServiceDescriptor { get; internal set; } + public List VirtualServiceIds { get; internal set; } + public string? BouquetList { get; internal set; } + + public override bool Equals(object? obj) + { + return obj is SgtService service && + ServiceListId == service.ServiceListId && + ServiceId == service.ServiceId && + TransportStreamId == service.TransportStreamId && + OriginalNetworkId == service.OriginalNetworkId; + } + + public override int GetHashCode() + { + return HashCode.Combine(ServiceListId, ServiceId, TransportStreamId, OriginalNetworkId); + } + + internal string GetName() + { + if (ServiceDescriptor == null) + return "???"; + + return ServiceDescriptor.ServiceName; + } + } +} diff --git a/skyscraper8/Skyscraper/Plugins/PluginManager.cs b/skyscraper8/Skyscraper/Plugins/PluginManager.cs index 28a9a8c..b1b9293 100644 --- a/skyscraper8/Skyscraper/Plugins/PluginManager.cs +++ b/skyscraper8/Skyscraper/Plugins/PluginManager.cs @@ -15,6 +15,7 @@ using skyscraper5.Skyscraper.Scraper.Storage; using skyscraper5.Skyscraper.Scraper.StreamAutodetection; using skyscraper5.src.Skyscraper.Scraper.Dns; using skyscraper5.T2MI; +using skyscraper8.yo3explorer; namespace skyscraper5.Skyscraper.Plugins { @@ -150,6 +151,7 @@ namespace skyscraper5.Skyscraper.Plugins private Type mpePluginType = typeof(ISkyscraperMpePlugin); private Type gpsReceiverFactoryType = typeof(IGpsReceiverFactory); private Type streamTypeAutodetectionContestantType = typeof(Contestant); + private Type filesystemProcessorType = typeof(FilesystemProcessorPlugin); private PluginPrioritySorter sorter = new PluginPrioritySorter(); private List _dnsParsers; @@ -249,6 +251,11 @@ namespace skyscraper5.Skyscraper.Plugins HandleDnsParser(type); continue; } + else if (type.IsAssignableTo(filesystemProcessorType)) + { + HandleFilesystemProcessor(type); + continue; + } throw new NotImplementedException(); } @@ -476,9 +483,30 @@ namespace skyscraper5.Skyscraper.Plugins } #endregion + #region yo3explorers + + private List filesystemProcessorPlugins; + private void HandleFilesystemProcessor(Type t) + { + if (filesystemProcessorPlugins == null) + filesystemProcessorPlugins = new List(); + + FilesystemProcessorPlugin child = (FilesystemProcessorPlugin)Activator.CreateInstance(t); + filesystemProcessorPlugins.Add(child); + } + + #endregion public Ini Ini { get; private set; } + public IReadOnlyList GetFilesystemProcessors() + { + if (filesystemProcessorPlugins == null) + return new List(); + + return filesystemProcessorPlugins.AsReadOnly(); + } + public IReadOnlyList GetDnsParsers() { if (_dnsParsers == null) diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index c696d25..22c1242 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -64,6 +64,9 @@ using skyscraper5.T2MI.Packets.AdressingFunctions; using skyscraper5.Teletext; using skyscraper5.Teletext.Vps; using skyscraper5.Teletext.Wss; +using skyscraper8.Ses; +using skyscraper8.yo3explorer; +using Tsubasa.IO; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; using RntParser = skyscraper5.Dvb.TvAnytime.RntParser; @@ -75,7 +78,7 @@ namespace skyscraper5.Skyscraper.Scraper UpdateNotificationEventHandler, DataCarouselEventHandler, RdsEventHandler, IScte35EventHandler, IAutodetectionEventHandler, IRstEventHandler, IRntEventHandler, IMultiprotocolEncapsulationEventHandler, ObjectCarouselEventHandler, T2MIEventHandler, IDisposable, IFrameGrabberEventHandler, IntEventHandler, IRctEventHandler, IGsEventHandler, ISkyscraperContext, IDocsisEventHandler, AbertisDecoderEventHandler, Id3Handler, - InteractionChannelHandler + InteractionChannelHandler, SgtEventHandler { public const bool ALLOW_STREAM_TYPE_AUTODETECTION = true; public const bool ALLOW_FFMPEG_FRAMEGRABBER = true; @@ -2389,5 +2392,43 @@ namespace skyscraper5.Skyscraper.Scraper { LogEvent(SkyscraperContextEvent.StreamTypeAutodetection, String.Format("PID 0x{0:X4} probably isn't a {1}", pid, contestant.Tag)); } - } + + void SgtEventHandler.AnnounceSgtList(SgtList list) + { + if (!ScraperStorage.TestForSgtList(list)) + { + LogEvent(SkyscraperContextEvent.SgtList, String.Format("List #{0} ({1})", list.ServiceListId, list.GetName())); + ScraperStorage.InsertSgtList(list); + } + } + + void SgtEventHandler.OnSgtError(SgtError invalidTableId) + { + throw new NotImplementedException(); + } + + void SgtEventHandler.OnSgtService(SgtService child) + { + if (!ScraperStorage.TestForSgtService(child)) + { + LogEvent(SkyscraperContextEvent.SgtService, String.Format("LCN #{0} in List #{1} ({2})", child.Lcn, child.ServiceListId, child.GetName())); + ScraperStorage.InsertSgtService(child); + } + } + + public void ProcessVirtualFilesystem(IFilesystem vfs, ProgramMappingStream programMappingStream) + { + yo3explorerState state = yo3explorerState.GetInstance(); + + yo3explorerToSkyscraperContextBridge context = new yo3explorerToSkyscraperContextBridge(); + + PluginManager pluginManager = PluginManager.GetInstance(); + IReadOnlyList processors = pluginManager.GetFilesystemProcessors(); + + foreach(FilesystemProcessorPlugin processor in processors) + { + processor.ProcessFilesystem(vfs, context, state); + } + } + } } diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs index d55b8a7..e7e2357 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs @@ -70,6 +70,8 @@ TimCorrection, TimContentionControl, TimCorrectionControl, - TimNetworkLayerInfo + TimNetworkLayerInfo, + SgtList, + SgtService } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemScraperStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemScraperStorage.cs index e9856d5..d7fa446 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemScraperStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemScraperStorage.cs @@ -33,6 +33,7 @@ using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.src.Skyscraper.Scraper.Dns; using skyscraper5.src.Skyscraper.Scraper.Storage.InMemory; using skyscraper5.Teletext; +using skyscraper8.Ses; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem @@ -1406,5 +1407,25 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem { throw new NotImplementedException(); } + + public bool TestForSgtList(SgtList list) + { + throw new NotImplementedException(); + } + + public void InsertSgtList(SgtList list) + { + throw new NotImplementedException(); + } + + public bool TestForSgtService(SgtService child) + { + throw new NotImplementedException(); + } + + public void InsertSgtService(SgtService child) + { + throw new NotImplementedException(); + } } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/IScraperStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/IScraperStorage.cs index 5fe5792..3b2dc77 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/IScraperStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/IScraperStorage.cs @@ -28,6 +28,7 @@ using skyscraper5.src.InteractionChannel.Model.Descriptors; using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.src.Skyscraper.Scraper.Dns; using skyscraper5.Teletext; +using skyscraper8.Ses; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; namespace skyscraper5.Skyscraper.Scraper.Storage @@ -175,5 +176,9 @@ namespace skyscraper5.Skyscraper.Scraper.Storage bool NetworkLayerInfoTim(PhysicalAddress mac, _0xa0_NetworkLayerInfoDescriptor nlid, DateTime timestamp); IEnumerable GetDbBlindscanJobs(); + bool TestForSgtList(SgtList list); + void InsertSgtList(SgtList list); + bool TestForSgtService(SgtService child); + void InsertSgtService(SgtService child); } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs index 0d36a32..de40da3 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs @@ -31,6 +31,8 @@ using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.src.Skyscraper.Scraper.Dns; using skyscraper5.src.Skyscraper.Scraper.Storage.InMemory; using skyscraper5.Teletext; +using skyscraper8.Ses; +using skyscraper8.Skyscraper.Scraper.Storage.InMemory.Model; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory @@ -1012,37 +1014,54 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory throw new NotImplementedException(); } + private HashSet jobs; public void InsertBlindscanJob(DbBlindscanJob jobInDb) { - throw new NotImplementedException(); + if (jobs == null) + jobs = new HashSet(); + + DbBlindscanJobContainer jobContainer = new DbBlindscanJobContainer(jobInDb); + jobs.Add(jobContainer); } public void UpdateJobState(DbBlindscanJob jobInDb) { - throw new NotImplementedException(); + } + public void InsertSearchResult(DbBlindscanJob jobInDb, bool satellite, SearchResult searchResult, int polarityIndex, SearchResult2 searchResult2) { - throw new NotImplementedException(); + DbBlindscanJobContainer dbBlindscanJobContainer = jobs.First(x => x.JobGuid.Equals(jobInDb.JobGuid)); + if (dbBlindscanJobContainer == null) + throw new Exception("Failed to find the job."); + + dbBlindscanJobContainer.AddSearchResult(satellite, searchResult, polarityIndex, searchResult2); } public void UpdateTransponderState(DbBlindscanJob jobInDb, bool satellite, SearchResult searchResult, BlindscanResultState blindscanResultState, SearchResult2 searchResult2) { - throw new NotImplementedException(); + } public void InsertTransponderService(DbBlindscanJob jobInDb, bool resultSatellite, SearchResult resultSr1, SearchResult2 resultSr2, HumanReadableService humanReadableService) { - throw new NotImplementedException(); - } + DbBlindscanJobContainer jobContainer = jobs.First(x => x.JobGuid.Equals(jobInDb.JobGuid)); + if (jobContainer == null) + throw new Exception("Failed to find the job."); - public bool TestForIncompleteJob() + DbBlindscanJobContainer.SearchResultContainer searchResultContainer = jobContainer.GetSearchResult(resultSatellite, resultSr1, resultSr2); + if (searchResultContainer == null) + throw new Exception("Failed to find the search result."); + searchResultContainer.AddService(humanReadableService); + } + + public bool TestForIncompleteJob() { - throw new NotImplementedException(); + return false; } public DbBlindscanJob GetPastBlindscanJob(long offset) @@ -1236,5 +1255,39 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory dnsRecords.Add(record); } + + private SgtList[] sgtLists; + public bool TestForSgtList(SgtList list) + { + if (sgtLists == null) + return false; + + return sgtLists[list.ServiceListId] != null; + } + + public void InsertSgtList(SgtList list) + { + if (sgtLists == null) + sgtLists = new SgtList[ushort.MaxValue]; + + sgtLists[list.ServiceListId] = list; + } + + private HashSet sgtServices; + public bool TestForSgtService(SgtService child) + { + if (sgtServices == null) + return false; + + return sgtServices.Contains(child); + } + + public void InsertSgtService(SgtService child) + { + if (sgtServices == null) + sgtServices = new HashSet(); + + sgtServices.Add(child); + } } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/Model/DbBlindscanJobContainer.cs b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/Model/DbBlindscanJobContainer.cs new file mode 100644 index 0000000..4db7060 --- /dev/null +++ b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/Model/DbBlindscanJobContainer.cs @@ -0,0 +1,122 @@ +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; +using skyscraper5.src.Skyscraper.FrequencyListGenerator; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Skyscraper.Scraper.Storage.InMemory.Model +{ + internal class DbBlindscanJobContainer + { + private DbBlindscanJob jobInDb; + private List searchResults; + + public DbBlindscanJobContainer(DbBlindscanJob jobInDb) + { + this.jobInDb = jobInDb; + } + + public override bool Equals(object? obj) + { + return obj is DbBlindscanJobContainer container && + EqualityComparer.Default.Equals(jobInDb, container.jobInDb); + } + + public override int GetHashCode() + { + return HashCode.Combine(jobInDb); + } + + internal void AddSearchResult(bool satellite, SearchResult searchResult, int polarityIndex, SearchResult2 searchResult2) + { + if (searchResults == null) + searchResults = new List(); + + searchResults.Add(new SearchResultContainer(satellite, searchResult, polarityIndex, searchResult2)); + } + + internal SearchResultContainer GetSearchResult(bool satellit, SearchResult searchResult, int polarityIndex, SearchResult2 searchResult2) + { + SearchResultContainer searchResultContainer = searchResults.First(x => x.Matches(satellit, searchResult, polarityIndex, searchResult2)); + return searchResultContainer; + } + + internal SearchResultContainer GetSearchResult(bool satellit, SearchResult searchResult, SearchResult2 searchResult2) + { + SearchResultContainer searchResultContainer = searchResults.First(x => x.Matches(satellit, searchResult, searchResult2)); + return searchResultContainer; + } + + public Guid JobGuid + { + get + { + return jobInDb.JobGuid; + } + } + + internal class SearchResultContainer + { + private bool satellite; + private SearchResult searchResult; + private int polarityIndex; + private SearchResult2 searchResult2; + private List services; + + public SearchResultContainer(bool satellite, SearchResult searchResult, int polarityIndex, SearchResult2 searchResult2) + { + this.satellite = satellite; + this.searchResult = searchResult; + this.polarityIndex = polarityIndex; + this.searchResult2 = searchResult2; + } + + public override bool Equals(object? obj) + { + return obj is SearchResultContainer container && + satellite == container.satellite && + EqualityComparer.Default.Equals(searchResult, container.searchResult) && + polarityIndex == container.polarityIndex && + EqualityComparer.Default.Equals(searchResult2, container.searchResult2); + } + + public override int GetHashCode() + { + return HashCode.Combine(satellite, searchResult, polarityIndex, searchResult2); + } + + public bool Matches(bool satellite, SearchResult searchResult, int polarityIndex, SearchResult2 searchResult2) + { + if (this.satellite != satellite) + return false; + if (!EqualityComparer.Default.Equals(searchResult, this.searchResult)) + return false; + if (this.polarityIndex != polarityIndex) + return false; + if (!EqualityComparer.Default.Equals(searchResult2, this.searchResult2)) + return false; + return true; + } + + public bool Matches(bool satellite, SearchResult searchResult,SearchResult2 searchResult2) + { + if (this.satellite != satellite) + return false; + if (!EqualityComparer.Default.Equals(searchResult, this.searchResult)) + return false; + if (!EqualityComparer.Default.Equals(searchResult2, this.searchResult2)) + return false; + return true; + } + + internal void AddService(HumanReadableService humanReadableService) + { + if (services == null) + services = new List(); + services.Add(humanReadableService); + } + } + } +} diff --git a/skyscraper8/Skyscraper/Scraper/Storage/Split/DataStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/Split/DataStorage.cs index 6733c4f..22c369a 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/Split/DataStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/Split/DataStorage.cs @@ -31,6 +31,7 @@ using skyscraper5.src.InteractionChannel.Model.Descriptors; using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.src.Skyscraper.Scraper.Dns; using skyscraper5.Teletext; +using skyscraper8.Ses; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; namespace skyscraper5.Skyscraper.Scraper.Storage.Split @@ -160,5 +161,9 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Split bool CorrectionControlTim(PhysicalAddress mac, _0xac_CorrectionControlDescriptor descriptor); bool NetworkLayerInfoTim(PhysicalAddress mac, _0xa0_NetworkLayerInfoDescriptor nlid, DateTime timestamp); IEnumerable GetDbBlindscanJobs(); + bool TestForSgtList(SgtList list); + void InsertSgtList(SgtList list); + bool TestForSgtService(SgtService child); + void InsertSgtService(SgtService child); } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/Split/SplitScraperStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/Split/SplitScraperStorage.cs index f877fc6..9c3d142 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/Split/SplitScraperStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/Split/SplitScraperStorage.cs @@ -28,6 +28,7 @@ using skyscraper5.src.InteractionChannel.Model.Descriptors; using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.src.Skyscraper.Scraper.Dns; using skyscraper5.Teletext; +using skyscraper8.Ses; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; namespace skyscraper5.Skyscraper.Scraper.Storage.Split @@ -862,5 +863,29 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Split { dataStorage.RememberDnsRecord(record); } + + [DebuggerStepThrough] + public bool TestForSgtList(SgtList list) + { + return dataStorage.TestForSgtList(list); + } + + [DebuggerStepThrough] + public void InsertSgtList(SgtList list) + { + dataStorage.InsertSgtList(list); + } + + [DebuggerStepThrough] + public bool TestForSgtService(SgtService child) + { + return dataStorage.TestForSgtService(child); + } + + [DebuggerStepThrough] + public void InsertSgtService(SgtService child) + { + dataStorage.InsertSgtService(child); + } } } diff --git a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/DataCarouselContestant.cs b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/DataCarouselContestant.cs index 8b72188..50e57d5 100644 --- a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/DataCarouselContestant.cs +++ b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/DataCarouselContestant.cs @@ -14,6 +14,7 @@ using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs; using skyscraper5.Mpeg2; using skyscraper5.Mpeg2.Psi.Model; using skyscraper5.Skyscraper.Plugins; +using Tsubasa.IO; namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants { @@ -60,12 +61,11 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants public void NotifyDownloadComplete(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion, Stream result, bool isObjectCarousel) { - Score += 2; + Score++; } public void DsmCcDoItNowEvent(ProgramMapping programMapping, StreamEventDescriptor descriptorListStreamEventDescriptor, int pid) { - Score++; } public void PreventDsmCcModuleRepetition(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion) @@ -106,5 +106,9 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants } skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new DataCarouselDecoder(programContext.Stream, programContext.Program, DataCarouselIntention.NoIntention, skyscraperContext))); } - } + + public void ProcessVirtualFilesystem(IFilesystem vfs, ProgramMappingStream pmtPid) + { + } + } } diff --git a/skyscraper8/skyscraper8.csproj b/skyscraper8/skyscraper8.csproj index f3cd44e..aa764c0 100644 --- a/skyscraper8/skyscraper8.csproj +++ b/skyscraper8/skyscraper8.csproj @@ -13,4 +13,8 @@ + + + + diff --git a/skyscraper8/yo3explorer/Filesystem.cs b/skyscraper8/yo3explorer/Filesystem.cs new file mode 100644 index 0000000..b76e0d2 --- /dev/null +++ b/skyscraper8/yo3explorer/Filesystem.cs @@ -0,0 +1,67 @@ +using skyscraper5.Dvb.DataBroadcasting.Biop; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace Tsubasa.IO +{ + /// + /// Represents a simple interface to a virtual filesystem. + /// + /// This interface is here as a memento to remember where Skyscraper originated from. + /// It was copied 1:1 from the source code of yo3explorer, a project I abandoned a long time ago, but is still dear to me. + ///yo3explorer was designed to extract game assets of Yu-Gi-Oh! ONLINE 3, a long defunct online game with a fully automatic simulation of the Yu-Gi-Oh! Trading Card Game. + ///The GUI of yo3explorer used this interface to talk to Archive Format parsers. + ///Eventually, yo3explorer grew to not only support Yu-Gi-Oh! ONLINE 3, but other games as well. + ///Some notable ones: + /// - Artificial Girl 3 + /// - Ever17: The out of infinity + /// - Jokei Kazoku III ~Himitsu~ + /// - Hyperdimension Neptunia Re; Birth + /// - Steins;Gate + /// - Yu-Gi-Oh! Power of Chaos + /// - Spelunky + /// - Super Heroine Chronicle + /// - Spocon! ~Sports Wear-Complex ~ + ///This interface is, at the time of adding this comment, over 10 years old. It was written on 24.12.2013 + /// + public interface IFilesystem : IDisposable + { + + /// + /// Checks whether a file by a specified name is present in a virtual filesystem. + /// + /// The filename to check for. + /// true if the file is present in the virtual filesystem, false if not. If filename appears in FileList this should return true. + bool FileExists(string filename); + + /// + /// Returns the contents of a file in a virtual filesystem. + /// + /// The filename of the file you want the contents of. + /// The file contents as a byte array. + byte[] GetFile(string filename); + + /// + /// All the names of the files contained in this virtual filesystem. + /// + string[] FileList + { + get; + } + + /// + /// A human readable name for this virutal filesystem. + /// + string FilesystemName + { + get; + } + } + +} \ No newline at end of file diff --git a/skyscraper8/yo3explorer/FilesystemProcessorPlugin.cs b/skyscraper8/yo3explorer/FilesystemProcessorPlugin.cs new file mode 100644 index 0000000..1ebf99d --- /dev/null +++ b/skyscraper8/yo3explorer/FilesystemProcessorPlugin.cs @@ -0,0 +1,24 @@ +using skyscraper5.Skyscraper.Scraper; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tsubasa.IO; + +namespace skyscraper8.yo3explorer +{ + /// + /// This interface is intended to describe a Skyscraper plugin that processes a yo3explorer compatible filesystem. + /// + internal interface FilesystemProcessorPlugin + { + /// + /// Lets this Skyscraper plugin process a yo3explorer compatible filesystem. + /// + /// A yo3explorer compatible filesystem. + /// Data that might be useful to the plugin. + /// Data that is supposed to be kept spanning multiple yo3explorer sessions. One could argue that this object simulates the GUI of yo3explorer. + void ProcessFilesystem(IFilesystem vfs, yo3explorerToSkyscraperContextBridge context, yo3explorerState state); + } +} diff --git a/skyscraper8/yo3explorer/yo3explorerState.cs b/skyscraper8/yo3explorer/yo3explorerState.cs new file mode 100644 index 0000000..76c7975 --- /dev/null +++ b/skyscraper8/yo3explorer/yo3explorerState.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.yo3explorer +{ + internal class yo3explorerState + { + private static yo3explorerState instance; + private yo3explorerState() + { + + } + + public static yo3explorerState GetInstance() + { + if (instance == null) + { + instance = new yo3explorerState(); + } + return instance; + } + } +} diff --git a/skyscraper8/yo3explorer/yo3explorerToSkyscraperContextBridge.cs b/skyscraper8/yo3explorer/yo3explorerToSkyscraperContextBridge.cs new file mode 100644 index 0000000..02dd7c3 --- /dev/null +++ b/skyscraper8/yo3explorer/yo3explorerToSkyscraperContextBridge.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.yo3explorer +{ + internal class yo3explorerToSkyscraperContextBridge + { + } +}