First attempts at scraping Freesat.

This commit is contained in:
feyris-tan 2025-07-05 22:26:42 +02:00
parent 1faa402dce
commit 226901607c
66 changed files with 8850 additions and 115 deletions

3
.gitignore vendored
View File

@ -110,3 +110,6 @@ imgui.ini
/.vs/skyscraper8/CopilotIndices/17.14.698.11175
/GUIs/skyscraper8.UI.ImGui/bin/Debug/net8.0
/.vs/skyscraper8/CopilotIndices/17.14.734.62261
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/bin/Debug/net8.0
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/obj/Debug/net8.0
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/obj

View File

@ -77,7 +77,7 @@
* Unbekanntes Text Encoding auf Eutelsat 7, 12648 H, MIS3
* [DONE] "Unknown Protocol" 50
* [DONE] "Unknown Protocal" 47
* In MinioObjectStorage.cs bei Zeile 132 - behandeln dass nicht immer unbedingt eine MinioException rauskommt!
* [DONE] In MinioObjectStorage.cs bei Zeile 132 - behandeln dass nicht immer unbedingt eine MinioException rauskommt!
* skyscraper5.Ietf.Rfc971.InternetHeader sollte Validatable implementieren.
* In Testdrid: Einen Notizblock
* Wenn ein Blindscan false zurückgibt, aber dennoch Ergebnisse geliefert hat, diese trotzdem abklopfen.
@ -133,8 +133,17 @@
* [DONE] IP-Protokoll 139 (skyscraper_20230408_1727_0390E_12739_H_3926_gse.ts)
* [DONE] DNS Record Type 20366 (skyscraper_20230410_1450_0660E_12626_V_38329.ts)
* [DONE] DNS IN ( {Z:\Freebies\Datasets\SkyscraperLibrarian\DVB-S August 2024\Telstar15\skyscraper_20240826_1530_0150W_12596_V_44999.ts} )
* ScraperStorage: Big File
* ScraperStorage: Big File mit Index
* [DONE] Für BigFiles: Gesplitteter Stream, für FAT32 und Freunde
* [DONE] Einen "Forget Blindscan Job" Button in der UI
* TransportProtocolDescriptor - unbekannte ProtocolIDs ohne Exception behandeln. (Vielleicht eine Warning?)
* TransportProtocolDescriptor - unbekannte ProtocolIDs ohne Exception behandeln. (Vielleicht eine Warning?)
* Weitere Datenbanktreiber
* Microsoft SQL Server
* Oracle
* Cassandra
* SQLite
* MongoDB
* Redis
* IBM DB2
* Firebird
* ScraperStorage: Big File
* ScraperStorage: Big File mit Index

View File

@ -0,0 +1,76 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
namespace DVBServices
{
/// <summary>
/// The class that describes a Huffman dictionary entry.
/// </summary>
public class HuffmanEntry
{
/// <summary>
/// Get or set the zero bit link.
/// </summary>
public HuffmanEntry P0
{
get { return (p0); }
set { p0 = value; }
}
/// <summary>
/// Get or set the one bit link.
/// </summary>
public HuffmanEntry P1
{
get { return (p1); }
set { p1 = value; }
}
/// <summary>
/// Get or set the entry value.
/// </summary>
public string Value
{
get { return (value); }
set
{
this.value = value;
holdsValue = true;
}
}
/// <summary>
/// Returns true if the value has been set; false otherwise.
/// </summary>
public bool HoldsValue { get { return (holdsValue); } }
private HuffmanEntry p0;
private HuffmanEntry p1;
private string value;
private bool holdsValue;
/// <summary>
/// Intialize a new instance of the HuffmanEntry.
/// </summary>
public HuffmanEntry() { }
}
}

View File

@ -0,0 +1,515 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.IO;
using System.Text;
using System.Globalization;
using System.Collections.ObjectModel;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes a dictionary entry for a multi-tree Hufmman scenario.
/// </summary>
public class MultiTreeDictionaryEntry
{
/// <summary>
/// Return true if the translation tables have been loaded; false otherwise.
/// </summary>
public static bool Loaded { get { return (loaded); } }
/// <summary>
/// Get the count of escape sequences for a text string.
/// </summary>
public static int EscapeCount { get; private set; }
private const int stop = 0x02;
private const int start = 0x00;
private const int escape = 0x01;
private static HuffmanEntry[] table1Roots = new HuffmanEntry[256];
private static HuffmanEntry[] table2Roots = new HuffmanEntry[256];
/// <summary>
/// Get the decode string.
/// </summary>
public string Decode { get { return (decode); } }
private string decode;
private string pattern;
private static bool loaded;
private static Collection<string> encodings;
private static int singleByteEscapes;
private static int multiByteEscapes;
/// <summary>
/// Initialize a new instance of the MultiTreeDictionaryEntry class.
/// </summary>
/// <param name="pattern">The Huffman bit pattern.</param>
/// <param name="decode">The decode for the bit pattern.</param>
public MultiTreeDictionaryEntry(string pattern, string decode)
{
this.pattern = pattern;
this.decode = decode;
}
/// <summary>
/// Load the reference tables.
/// </summary>
/// <param name="fileName1">The full name of the T1 file.</param>
/// <param name="fileName2">The full name of the T2 file.</param>
/// <returns>True if the file is loaded successfully;false otherwise.</returns>
public static bool Load(Stream fileName1, Stream fileName2)
{
if (loaded)
return (true);
Logger.Instance.Write("Loading Huffman Dictionary 1");
try
{
loadFile(table1Roots, fileName1);
}
catch (IOException e)
{
Logger.Instance.Write("Huffman Dictionary file not available");
Logger.Instance.Write(e.Message);
return (false);
}
Logger.Instance.Write("Loading Huffman Dictionary 2 from " + fileName2);
try
{
loadFile(table2Roots, fileName2);
}
catch (IOException e)
{
Logger.Instance.Write("Huffman Dictionary file not available");
Logger.Instance.Write(e.Message);
return (false);
}
Logger.Instance.Write("Dictionaries loaded");
loaded = true;
return (true);
}
private static void loadFile(HuffmanEntry[] roots, Stream fileStream)
{
StreamReader streamReader = new StreamReader(fileStream);
while (!streamReader.EndOfStream)
{
string line = streamReader.ReadLine();
if (line != string.Empty && !line.StartsWith("####"))
{
string[] parts = line.Split(new char[] { ':' });
if (parts.Length == 4)
{
int rootOffSet = (int)(resolveChar(parts[0]));
if (roots[rootOffSet] == null)
roots[rootOffSet] = new HuffmanEntry();
HuffmanEntry currentEntry = roots[rootOffSet];
string pattern = parts[1];
for (int index = 0; index < parts[1].Length; index++)
{
char patternChar = pattern[index];
switch (patternChar)
{
case '0':
if (currentEntry.P0 == null)
{
currentEntry.P0 = new HuffmanEntry();
currentEntry = currentEntry.P0;
if (index == pattern.Length - 1)
currentEntry.Value = resolveChar(parts[2]).ToString();
}
else
{
currentEntry = currentEntry.P0;
if (currentEntry.HoldsValue && index == pattern.Length - 1)
Logger.Instance.Write("Dictionary entry already set");
}
break;
case '1':
if (currentEntry.P1 == null)
{
currentEntry.P1 = new HuffmanEntry();
currentEntry = currentEntry.P1;
if (index == pattern.Length - 1)
currentEntry.Value = resolveChar(parts[2]).ToString();
}
else
{
currentEntry = currentEntry.P1;
if (currentEntry.HoldsValue && index == pattern.Length - 1)
Logger.Instance.Write("Dictionary entry already set: " + line);
}
break;
default:
break;
}
}
}
}
}
streamReader.Close();
fileStream.Close();
}
/// <summary>
/// Decode a Multi-tree text string which includes the text prefix (ie 0x1f?? where ?? indicates the table number 1 or 2).
/// </summary>
/// <param name="byteData">The encoded string.</param>
/// <param name="encoding">The encoding used for the decompressed bytes.</param>
/// <returns>The decoded string.</returns>
public static string DecodeData(byte[] byteData, string encoding)
{
if (byteData[1] == 1)
return(decodeData(byteData, table1Roots, 2, encoding));
else
return(decodeData(byteData, table2Roots, 2, encoding));
}
/// <summary>
/// Decode a Multi-tree text string with no prefix.
/// </summary>
/// <param name="table">The decode table to use (1 or 2).</param>
/// <param name="byteData">The encoded string.</param>
/// <param name="encoding">The encoding used for the decompressed bytes.</param>
/// <returns>The decoded string.</returns>
public static string DecodeData(int table, byte[] byteData, string encoding)
{
if (table == 1)
return (decodeData(byteData, table1Roots, 0, encoding));
else
return (decodeData(byteData, table2Roots, 0, encoding));
}
private static string decodeData(byte[] byteData, HuffmanEntry[] roots, int startIndex, string encoding)
{
byte[] decompressedBytes = getByteBuffer(null);
int decompressedIndex = 0;
Encoding sourceEncoding = sourceEncoding = Encoding.GetEncoding(encoding);
if (encodings == null)
encodings = new Collection<string>();
if (!encodings.Contains(encoding))
encodings.Add(encoding);
HuffmanEntry currentEntry = roots[0];
byte mask = 0x80;
bool finished = false;
EscapeCount = 0;
for (int index = startIndex; index < byteData.Length && !finished; index++)
{
byte dataByte = byteData[index];
while (mask > 0 && !finished)
{
if (currentEntry.HoldsValue)
{
switch ((int)currentEntry.Value[0])
{
case stop:
finished = true;
break;
case escape:
bool escapeDone = false;
while (!escapeDone)
{
byte encodedValue = 0x00;
for (int bitCount = 0; bitCount < 8; bitCount++)
{
encodedValue = (byte)(encodedValue << 1);
if ((dataByte & mask) != 0)
encodedValue |= 0x01;
mask = (byte)(mask >> 1);
if (mask == 0)
{
index++;
if (index >= byteData.Length)
{
//This if condition was added by feyris-tan
//to prevent random crash.
finished = true;
bitCount = 8;
escapeDone = true;
continue;
}
dataByte = byteData[index];
mask = 0x80;
}
}
if (encodedValue > 0x1f)
decompressedBytes = storeDecompressedByte(encodedValue, decompressedBytes, ref decompressedIndex);
int length;
if ((encodedValue & 0xe0) == 0xc0) // UTF-8 2 bytes
length = 2;
else
{
if ((encodedValue & 0xf0) == 0xe0) // UTF-8 3 bytes
length = 3;
else
{
if ((encodedValue & 0xf8) == 0xf0) // UTF-8 4 bytes
length = 4;
else
length = 1; // ASCII byte
}
}
if (DebugEntry.IsDefined(DebugName.LogHuffman))
Logger.Instance.Write("HD: Escaped length is " + length + " byte 0 encoded value was 0x" + encodedValue.ToString("x"));
if (length == 1)
singleByteEscapes++;
else
{
multiByteEscapes++;
EscapeCount++;
}
while (length > 1)
{
encodedValue = 0x00;
for (int bitCount = 0; bitCount < 8; bitCount++)
{
encodedValue = (byte)(encodedValue << 1);
if ((dataByte & mask) != 0)
encodedValue |= 0x01;
mask = (byte)(mask >> 1);
if (mask == 0)
{
index++;
dataByte = byteData[index];
mask = 0x80;
}
}
decompressedBytes = storeDecompressedByte(encodedValue, decompressedBytes, ref decompressedIndex);
if (DebugEntry.IsDefined(DebugName.LogHuffman) && length > 1)
Logger.Instance.Write("HD: byte encoded value was 0x" + encodedValue.ToString("x"));
length--;
}
if (encodedValue < 0x20)
{
/*finished = true;
escapeDone = true;*/
currentEntry = roots[encodedValue];
escapeDone = true;
}
else
{
if (encodedValue < 0x80)
{
currentEntry = roots[encodedValue];
escapeDone = true;
}
}
}
break;
default:
decompressedBytes = storeDecompressedByte((byte)currentEntry.Value[0], decompressedBytes, ref decompressedIndex);
currentEntry = roots[(int)currentEntry.Value[0]];
break;
}
}
if (!finished)
{
if ((dataByte & mask) == 0)
{
if (currentEntry != null && currentEntry.P0 != null)
currentEntry = currentEntry.P0;
else
{
string outputString = sourceEncoding.GetString(decompressedBytes, 0, decompressedIndex);
Logger.Instance.Write(" ** DECOMPRESSION FAILED **");
Logger.Instance.Write("Original data: " + Utils.ConvertToHex(byteData));
Logger.Instance.Write("Decoded data: " + outputString.ToString());
return (outputString.ToString() + " ** DECOMPRESSION FAILED **");
}
}
else
{
if (currentEntry != null && currentEntry.P1 != null)
currentEntry = currentEntry.P1;
else
{
string outputString = sourceEncoding.GetString(decompressedBytes, 0, decompressedIndex);
Logger.Instance.Write(" ** DECOMPRESSION FAILED **");
Logger.Instance.Write("Original data: " + Utils.ConvertToHex(byteData));
Logger.Instance.Write("Decoded data: " + outputString.ToString());
return (outputString.ToString() + " ** DECOMPRESSION FAILED **");
}
}
mask = (byte)(mask >> 1);
}
}
mask = 0x80;
}
if (decompressedIndex != 0)
{
string response = sourceEncoding.GetString(decompressedBytes, 0, decompressedIndex);
/*if (WasEscaped)
Logger.Instance.Write("HD: " + response);*/
return (response);
}
else
return (string.Empty);
}
private static byte[] storeDecompressedByte(byte decompressedByte, byte[] decompressedBytes, ref int decompressedIndex)
{
if (decompressedByte == 0x00)
return (decompressedBytes);
byte[] outputBuffer;
if (decompressedIndex > decompressedBytes.Length)
outputBuffer = getByteBuffer(decompressedBytes);
else
outputBuffer = decompressedBytes;
outputBuffer[decompressedIndex] = decompressedByte;
decompressedIndex++;
return (outputBuffer);
}
private static byte[] getByteBuffer(byte[] existingBuffer)
{
int size = 1024;
if (existingBuffer != null)
size += existingBuffer.Length;
byte[] newBuffer = new byte[size];
if (existingBuffer != null)
Array.Copy(existingBuffer, newBuffer, existingBuffer.Length);
return (newBuffer);
}
private static char resolveChar(string input)
{
int val = new int();
char myChar = input[0]; //default value
switch (input.ToUpper())
{
case "START":
myChar = (char)0x00;
break;
case "STOP":
myChar = (char)0x02;
break;
case "ESCAPE":
myChar = (char)0x01;
break;
default:
try
{
if (input.Length > 2)
{
if (input.Substring(0, 2) == "0x")
{
val = int.Parse(input.Substring(2, input.Length - 2),
NumberStyles.AllowHexSpecifier); //ASCII for the input character
}
myChar = (char)val;
}
}
catch (Exception e)
{
Logger.Instance.Write("OMG WUT: {0}" + e.Message);
}
break;
}
return (myChar);
}
/// <summary>
/// Log the decoding usage.
/// </summary>
public static void LogUsage()
{
if (encodings == null)
return;
Logger.Instance.WriteSeparator("Huffman Usage");
StringBuilder text = new StringBuilder();
foreach (string encoding in encodings)
{
if (text.Length != 0)
text.Append(", ");
text.Append(encoding);
}
Logger.Instance.Write("Huffman encodings used: " + text);
Logger.Instance.Write("Huffman single byte escape sequences: " + singleByteEscapes);
Logger.Instance.Write("Huffman multi byte escape sequences: " + multiByteEscapes);
Logger.Instance.WriteSeparator("End Of Huffman Usage");
encodings = null;
singleByteEscapes = 0;
multiByteEscapes = 0;
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DVBServices
{
internal class Utils
{
/// <summary>
/// Convert a string of bytes to a hex string.
/// </summary>
/// <param name="inputChars">The string to be converted.</param>
/// <returns>The string of hex characters.</returns>
public static string ConvertToHex(byte[] inputChars)
{
return (ConvertToHex(inputChars, inputChars.Length));
}
/// <summary>
/// Convert a string of bytes to a hex string.
/// </summary>
/// <param name="inputChars">The array holding the bytes to be converted.</param>
/// <param name="length">The number of byte to be converted.</param>
/// <returns>The string of hex characters.</returns>
public static string ConvertToHex(byte[] inputChars, int length)
{
return (ConvertToHex(inputChars, 0, length));
}
/// <summary>
/// Convert a string of bytes to a hex string.
/// </summary>
/// <param name="inputChars">The array holding the bytes to be converted.</param>
/// <param name="offset">The the offset to the first byte to be converted.</param>
/// <param name="length">The number of byte to be converted.</param>
/// <returns>The string of hex characters.</returns>
public static string ConvertToHex(byte[] inputChars, int offset, int length)
{
char[] outputChars = new char[length * 2];
int outputIndex = 0;
for (int inputIndex = 0; inputIndex < length; inputIndex++)
{
int hexByteLeft = inputChars[offset] >> 4;
int hexByteRight = inputChars[offset] & 0x0f;
outputChars[outputIndex] = getHex(hexByteLeft);
outputChars[outputIndex + 1] = getHex(hexByteRight);
outputIndex += 2;
offset++;
}
return ("0x" + new string(outputChars));
}
private static char getHex(int value)
{
if (value < 10)
return ((char)('0' + value));
return ((char)('a' + (value - 10)));
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DomainObjects
{
internal class DebugEntry
{
public static bool IsDefined(DebugName name)
{
return true;
}
}
}

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper8.Skyscraper.Plugins;
namespace DomainObjects
{
internal class Logger
{
private static Logger _instance;
public static Logger Instance
{
get
{
if(_instance == null)
_instance = new Logger();
return _instance;
}
}
private class EPGCollector
{
}
private PluginLogger _realLogger;
private Logger()
{
_realLogger = PluginLogManager.GetLogger(typeof(EPGCollector));
}
public void Write(string s)
{
_realLogger.Log(PluginLogLevel.All, s);
}
/// <summary>
/// Write a log separator line.
/// </summary>
/// <param name="identity">The text of the separator.</param>
public void WriteSeparator(string identity)
{
Write("");
Write("============================ " + identity + " ==============================");
Write("");
}
}
}

View File

@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace skyscraper8.EPGCollectorPort.Properties {
using System;
/// <summary>
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
/// </summary>
// Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
// -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
// mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("skyscraper8.EPGCollectorPort.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
/// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
/// </summary>
internal static byte[] Huffman_Dictionary_Freesat_T1 {
get {
object obj = ResourceManager.GetObject("Huffman Dictionary Freesat T1", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
/// </summary>
internal static byte[] Huffman_Dictionary_Freesat_T2 {
get {
object obj = ResourceManager.GetObject("Huffman Dictionary Freesat T2", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Huffman Dictionary Freesat T1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Huffman Dictionary Freesat T1.cfg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Huffman Dictionary Freesat T2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Huffman Dictionary Freesat T2.cfg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

View File

@ -0,0 +1,60 @@
using skyscraper5.Dvb.Psi;
using skyscraper5.Mpeg2;
using skyscraper5.Mpeg2.Descriptors;
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.EPGCollectorPort.SkyscraperSide
{
[SkyscraperPlugin]
internal class FreesatBatSdtContestant : Contestant
{
public FreesatBatSdtContestant(int pid) : base("Freesat BAT/SDT", pid)
{
}
public override void Dispose()
{
}
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
FreesatTunnelScraper freesatScraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is FreesatTunnelScraper) as FreesatTunnelScraper;
if (freesatScraper == null)
{
freesatScraper = new FreesatTunnelScraper();
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
skyscraperContext.PluginContext.Add(freesatScraper);
}
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new TimetableParser(freesatScraper, freesatScraper)));
}
public override void Introduce(ProgramContext programContext)
{
if (programContext.PrivateDataSpecifier == 0x46534154)
{
UserDefinedDescriptor userDefinedDescriptor = programContext.GetFirstUserDefinedDescriptor();
if (userDefinedDescriptor.DescriptorTag == 0xd1)
{
if (userDefinedDescriptor.Data[0] == 0x03)
{
if (userDefinedDescriptor.Data[1] == 0x04)
{
//Mine.
Score += 10;
return;
}
}
}
}
Score = -100;
}
}
}

View File

@ -0,0 +1,58 @@
using skyscraper5.Dvb.Psi;
using skyscraper5.Mpeg2;
using skyscraper5.Mpeg2.Descriptors;
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.EPGCollectorPort.SkyscraperSide
{
[SkyscraperPlugin]
internal class FreesatEpgContestant : Contestant
{
public FreesatEpgContestant(int pid)
: base("Freesat EPG", pid)
{
}
public override void Dispose()
{
}
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
FreesatTunnelScraper freesatScraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is FreesatTunnelScraper) as FreesatTunnelScraper;
if (freesatScraper == null)
{
freesatScraper = new FreesatTunnelScraper();
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
skyscraperContext.PluginContext.Add(freesatScraper);
}
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new EitParser(freesatScraper)));
}
public override void Introduce(ProgramContext programContext)
{
if (programContext.PrivateDataSpecifier == 0x46534154)
{
UserDefinedDescriptor userDefinedDescriptor = programContext.GetFirstUserDefinedDescriptor();
if (userDefinedDescriptor.DescriptorTag == 0xd1)
{
if (userDefinedDescriptor.Data[0] == 0x01 || userDefinedDescriptor.Data[0] == 0x02)
{
//Mine.
Score += 10;
return;
}
}
}
Score = -100;
}
}
}

View File

@ -0,0 +1,58 @@
using skyscraper5.Dvb.Psi;
using skyscraper5.Mpeg2;
using skyscraper5.Mpeg2.Descriptors;
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.EPGCollectorPort.SkyscraperSide
{
[SkyscraperPlugin]
internal class FreesatNitContestant : Contestant
{
public FreesatNitContestant(int pid)
: base("Freesat Network Information", pid)
{
}
public override void Dispose()
{
}
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
FreesatTunnelScraper freesatScraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is FreesatTunnelScraper) as FreesatTunnelScraper;
if (freesatScraper == null)
{
freesatScraper = new FreesatTunnelScraper();
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
skyscraperContext.PluginContext.Add(freesatScraper);
}
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new NitParser(freesatScraper)));
}
public override void Introduce(ProgramContext programContext)
{
if (programContext.PrivateDataSpecifier == 0x46534154)
{
UserDefinedDescriptor userDefinedDescriptor = programContext.GetFirstUserDefinedDescriptor();
if (userDefinedDescriptor.DescriptorTag == 0xd1)
{
if (userDefinedDescriptor.Data[0] == 0x07)
{
//Mine.
Score += 10;
return;
}
}
}
Score = -100;
}
}
}

View File

@ -0,0 +1,61 @@
using skyscraper5.Mpeg2.Descriptors;
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;
using skyscraper5.Dvb.Psi;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Plugins;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
{
[SkyscraperPlugin]
internal class FreesatTdtContestant : Contestant
{
public FreesatTdtContestant(int pid)
: base("Freesat Timestamp", pid)
{
}
public override void Dispose()
{
}
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
FreesatTunnelScraper freesatScraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is FreesatTunnelScraper) as FreesatTunnelScraper;
if (freesatScraper == null)
{
freesatScraper = new FreesatTunnelScraper();
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
skyscraperContext.PluginContext.Add(freesatScraper);
}
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new TimetableParser(freesatScraper, freesatScraper)));
}
public override void Introduce(ProgramContext programContext)
{
if (programContext.PrivateDataSpecifier == 0x46534154)
{
UserDefinedDescriptor userDefinedDescriptor = programContext.GetFirstUserDefinedDescriptor();
if (userDefinedDescriptor.DescriptorTag == 0xd1)
{
if (userDefinedDescriptor.Data[0] == 0x05)
{
if (userDefinedDescriptor.Data[1] == 0x06)
{
//Mine.
Score += 10;
return;
}
}
}
}
Score = -100;
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DVBServices;
using skyscraper5.Skyscraper.Plugins;
using skyscraper8.EPGCollectorPort.Properties;
using skyscraper8.Skyscraper.Text;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
{
[SkyscraperPlugin]
[EncodingTypeId(0x01)]
[EncodingTypeId(0x02)]
internal class FreesatTextDecoder : TextDecoder
{
public FreesatTextDecoder()
{
if (!MultiTreeDictionaryEntry.Loaded)
{
MemoryStream t1 = new MemoryStream(Resources.Huffman_Dictionary_Freesat_T1, false);
MemoryStream t2 = new MemoryStream(Resources.Huffman_Dictionary_Freesat_T2, false);
MultiTreeDictionaryEntry.Load(t1, t2);
t1.Dispose();
t2.Dispose();
}
}
public string Decode(byte[] buffer)
{
return MultiTreeDictionaryEntry.DecodeData(buffer, "utf-8");
}
}
}

View File

@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Dvb.Psi.Model;
using skyscraper5.Ietf.Rfc971;
using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
{
internal interface IFreesatTunnelDataStorage
{
bool StoreEitEvent(EitEvent eitEvent);
void StoreNitNetwork(NitNetwork nitNetwork);
bool TestNitNetwork(NitNetwork nitNetwork);
bool TestForNitTransportStream(ushort networkId, NitTransportStream transportStream);
void StoreNitTransportStream(ushort networkId, NitTransportStream transportStream);
}
internal class FreesatTunnelDataStorage : IFreesatTunnelDataStorage
{
public FreesatTunnelDataStorage(object[] getPluginConnector)
{
object o = getPluginConnector[0];
switch (o)
{
case InMemoryPluginToken t1:
_storageEngine = new FreesatTunnelDataStorageInMemory();
break;
default:
throw new NotImplementedException(o.GetType().FullName);
}
}
private IFreesatTunnelDataStorage _storageEngine;
public bool StoreEitEvent(EitEvent eitEvent)
{
return _storageEngine.StoreEitEvent(eitEvent);
}
public void StoreNitNetwork(NitNetwork nitNetwork)
{
_storageEngine.StoreNitNetwork(nitNetwork);
}
public bool TestNitNetwork(NitNetwork nitNetwork)
{
return _storageEngine.TestNitNetwork(nitNetwork);
}
public bool TestForNitTransportStream(ushort networkId, NitTransportStream transportStream)
{
return _storageEngine.TestForNitTransportStream(networkId, transportStream);
}
public void StoreNitTransportStream(ushort networkId, NitTransportStream transportStream)
{
_storageEngine.StoreNitTransportStream(networkId, transportStream);
}
}
internal class FreesatTunnelDataStorageInMemory : IFreesatTunnelDataStorage
{
private HashSet<EitEvent> _eitEvents;
public bool StoreEitEvent(EitEvent eitEvent)
{
if (_eitEvents == null)
_eitEvents = new HashSet<EitEvent>();
return _eitEvents.Add(eitEvent);
}
private NitNetwork[] _nitNetworks;
public void StoreNitNetwork(NitNetwork nitNetwork)
{
if (_nitNetworks == null)
_nitNetworks = new NitNetwork[ushort.MaxValue];
_nitNetworks[nitNetwork.NetworkId] = nitNetwork;
}
public bool TestNitNetwork(NitNetwork nitNetwork)
{
if (_nitNetworks == null)
return false;
return _nitNetworks[nitNetwork.NetworkId] != null;
}
private NitTransportStream[][] _nitTransportStreams;
public bool TestForNitTransportStream(ushort networkId, NitTransportStream transportStream)
{
if (_nitTransportStreams == null)
return false;
if (_nitTransportStreams[networkId] == null)
return false;
return _nitTransportStreams[networkId][transportStream.TransportStreamId] != null;
}
public void StoreNitTransportStream(ushort networkId, NitTransportStream transportStream)
{
if (_nitTransportStreams == null)
_nitTransportStreams = new NitTransportStream[ushort.MaxValue][];
if (_nitTransportStreams[networkId] == null)
_nitTransportStreams[networkId] = new NitTransportStream[ushort.MaxValue];
}
}
}

View File

@ -0,0 +1,115 @@
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi;
using skyscraper5.Dvb.Psi.Model;
using skyscraper8.EPGCollectorPort.SkyscraperSide;
using skyscraper8.Skyscraper.Scraper.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper8.Skyscraper.Plugins;
namespace skyscraper5.Skyscraper.Scraper
{
internal class FreesatTunnelScraper : IBatEventHandler, ISdtEventHandler, ITdtEventHandler, ITotEventHandler, IEitEventHandler, INitEventHandler
{
public void OnBatBouquet(BatBouquet batBouquet)
{
throw new NotImplementedException();
}
public void OnBatTransportStream(BatBouquet batBouquet, BatTransportStream child)
{
throw new NotImplementedException();
}
public void OnSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService sdtService)
{
throw new NotImplementedException();
}
public void OnTdtTime(DateTime utcTime)
{
if (!networkId.HasValue)
return;
if (!transportStreamId.HasValue)
return;
throw new NotImplementedException();
}
public void OnTotTime(DateTime utcTime, LocalTimeOffsetDescriptor ltod)
{
if (!networkId.HasValue)
return;
if (!transportStreamId.HasValue)
return;
throw new NotImplementedException();
}
private ushort? networkId;
public void SetNetworkId(ushort networkId)
{
throw new NotImplementedException();
}
private ushort? transportStreamId;
public void SetTransportStreamId(ushort transportStreamId)
{
throw new NotImplementedException();
}
public void SetNetworkId(ushort networkId, bool forceOverwrite = false)
{
throw new NotImplementedException();
}
public void OnNitTransportStream(ushort networkId, NitTransportStream transportStream)
{
if (!_dataStorage.TestForNitTransportStream(networkId, transportStream))
{
_logger.Log(PluginLogLevel.Info, "NIT Network {0} Transport Stream {1}", networkId, transportStream.TransportStreamId);
_dataStorage.StoreNitTransportStream(networkId, transportStream);
}
}
public void OnNitNetwork(NitNetwork nitNetwork)
{
if (!_dataStorage.TestNitNetwork(nitNetwork))
{
_logger.Log(PluginLogLevel.Info, "NIT Network {0}", nitNetwork.NetworkId);
_dataStorage.StoreNitNetwork(nitNetwork);
}
}
private EitEvent[] runningEvents;
public void OnEitEvent(EitEvent eitEvent)
{
if (_dataStorage.StoreEitEvent(eitEvent))
{
_logger.Log(PluginLogLevel.Info, "EIT Event: {0}", eitEvent.EventName);
}
if (eitEvent.RunningStatus == RunningStatus.Running)
{
if (runningEvents == null)
runningEvents = new EitEvent[UInt16.MaxValue];
runningEvents[eitEvent.ServiceId] = eitEvent;
}
}
private PluginLogger _logger;
private IFreesatTunnelDataStorage _dataStorage;
public void ConnectToStorage(object[] getPluginConnector)
{
if (_dataStorage == null)
{
_dataStorage = new FreesatTunnelDataStorage(getPluginConnector);
}
_logger = PluginLogManager.GetLogger(this.GetType());
}
}
}

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\skyscraper8\skyscraper8.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -59,6 +59,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper5.UI.WindowsForms
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.UI.ImGui", "GUIs\skyscraper8.UI.ImGui\skyscraper8.UI.ImGui.csproj", "{BDBDB7A9-D0A4-9B89-0801-2935B2066551}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.EPGCollectorPort", "PrivateDataSpecifiers\skyscraper8.EPGCollectorPort\skyscraper8.EPGCollectorPort.csproj", "{CF21D250-9804-4191-89F5-95821E3AF39D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -145,6 +147,10 @@ Global
{BDBDB7A9-D0A4-9B89-0801-2935B2066551}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDBDB7A9-D0A4-9B89-0801-2935B2066551}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDBDB7A9-D0A4-9B89-0801-2935B2066551}.Release|Any CPU.Build.0 = Release|Any CPU
{CF21D250-9804-4191-89F5-95821E3AF39D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF21D250-9804-4191-89F5-95821E3AF39D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF21D250-9804-4191-89F5-95821E3AF39D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF21D250-9804-4191-89F5-95821E3AF39D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -168,6 +174,7 @@ Global
{8F17668C-623C-F9B3-EAD4-2922E5414B75} = {E00647B6-4509-4A1C-A7CB-D0C72325D23E}
{46CACA1C-F9B2-2FE0-2068-716F381325E9} = {E23457C5-3A34-48EE-8107-C91E2C174B2D}
{BDBDB7A9-D0A4-9B89-0801-2935B2066551} = {E23457C5-3A34-48EE-8107-C91E2C174B2D}
{CF21D250-9804-4191-89F5-95821E3AF39D} = {56729C39-B90E-4DF3-A557-DB93436FB5FF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5147EFA3-3D4E-4FDE-8A36-5840E8F1B80E}

View File

@ -7,7 +7,7 @@ using skyscraper5.Dvb.Psi.Model;
namespace skyscraper5.Dvb.Psi
{
interface IBatEventHandler
public interface IBatEventHandler
{
void OnBatBouquet(BatBouquet batBouquet);
void OnBatTransportStream(BatBouquet batBouquet, BatTransportStream child);

View File

@ -2,7 +2,7 @@
namespace skyscraper5.Dvb.Psi
{
interface IEitEventHandler
public interface IEitEventHandler
{
void SetTransportStreamId(ushort transportStreamId);
void SetNetworkId(ushort networkId, bool forceOverwrite = false);

View File

@ -12,7 +12,7 @@ using skyscraper5.Skyscraper.Plugins;
namespace skyscraper5.Dvb.Psi
{
class EitParser : IPsiProcessor
public class EitParser : IPsiProcessor
{
public EitParser(IEitEventHandler eventHandler)
{

View File

@ -7,7 +7,7 @@ using skyscraper5.Dvb.Psi.Model;
namespace skyscraper5.Dvb.Psi
{
interface INitEventHandler
public interface INitEventHandler
{
void SetNetworkId(ushort networkId, bool forceOverrite = false);
void OnNitTransportStream(ushort networkId, NitTransportStream transportStream);

View File

@ -12,7 +12,7 @@ using skyscraper5.Skyscraper.Plugins;
namespace skyscraper5.Dvb.Psi
{
class NitParser : IPsiProcessor
public class NitParser : IPsiProcessor
{
public INitEventHandler EventHandler { get; }

View File

@ -7,7 +7,7 @@ using skyscraper5.Dvb.Psi.Model;
namespace skyscraper5.Dvb.Psi
{
interface ISdtEventHandler
public interface ISdtEventHandler
{
void OnSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService sdtService);
void SetNetworkId(ushort networkId);

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace skyscraper5.Dvb.Psi
{
interface ITdtEventHandler
public interface ITdtEventHandler
{
void OnTdtTime(DateTime utcTime);
}

View File

@ -10,7 +10,7 @@ using skyscraper5.Skyscraper.IO;
namespace skyscraper5.Dvb.Psi
{
class TimetableParser : IPsiProcessor
public class TimetableParser : IPsiProcessor
{
public ITdtEventHandler TdtEventHandler { get; }
public ITotEventHandler TotEventHandler { get; }

View File

@ -7,7 +7,7 @@ using skyscraper5.Dvb.Descriptors;
namespace skyscraper5.Dvb.Psi
{
interface ITotEventHandler
public interface ITotEventHandler
{
void OnTotTime(DateTime utcTime, LocalTimeOffsetDescriptor ltod);
}

View File

@ -2,6 +2,7 @@
"profiles": {
"skyscraper8": {
"commandName": "Project",
"commandLineArgs": "\"Z:\\Freebies\\Datasets\\SkyscraperLibrarian\\DVB-S August 2024\\Astra28\\skyscraper_20240829_0651_0283E_10714_H_21999.ts\"",
"remoteDebugEnabled": false
},
"Container (Dockerfile)": {

View File

@ -25,6 +25,11 @@ namespace skyscraper8.Ses
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new SgtParser(skyscraperContext)));
}
public override void Introduce(ProgramContext programContext)
{
}
public override void Dispose()
{
}

View File

@ -41,7 +41,7 @@ namespace skyscraper8.Skyscraper.Plugins
Logger.DebugFormat(message, a);
break;
case PluginLogLevel.All:
Console.WriteLine(message, a);
//Console.WriteLine(message, a);
break;
default:
throw new NotImplementedException(level.ToString());

View File

@ -18,6 +18,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using skyscraper8.Skyscraper.Scraper.Storage;
using skyscraper8.Skyscraper.Text;
namespace skyscraper5.Skyscraper.Plugins
{
@ -157,6 +158,7 @@ namespace skyscraper5.Skyscraper.Plugins
private Type gpsReceiverFactoryType = typeof(IGpsReceiverFactory);
private Type streamTypeAutodetectionContestantType = typeof(Contestant);
private Type filesystemProcessorType = typeof(FilesystemProcessorPlugin);
private Type textDecoderType = typeof(TextDecoder);
private PluginPrioritySorter sorter = new PluginPrioritySorter();
private List<IDnsParser> _dnsParsers;
@ -172,6 +174,7 @@ namespace skyscraper5.Skyscraper.Plugins
private Tuple<ConstructorInfo, ExtensionDescriptorAttribute>[] _extensionDescriptors;
private ConstructorInfo[] _dsmCcMessages;
private ConstructorInfo[] _mpeg2ExtensionDescriptors;
private TextDecoder[] _textDecoders;
private void ScanAssembly(Assembly assembly)
{
@ -272,13 +275,39 @@ namespace skyscraper5.Skyscraper.Plugins
HandleFilesystemProcessor(type);
continue;
}
else if (type.IsAssignableTo(textDecoderType))
{
HandleTextDecoder(type);
continue;
}
throw new NotImplementedException();
throw new NotImplementedException();
}
_mpePlugins.Sort(sorter);
}
private void HandleTextDecoder(Type type)
{
List<EncodingTypeIdAttribute> idAttributes = type.GetCustomAttributes<EncodingTypeIdAttribute>().ToList();
if (idAttributes == null || idAttributes.Count == 0)
{
logger.ErrorFormat("{0} does not have any {1}", type.Name, nameof(EncodingTypeIdAttribute));
return;
}
if (_textDecoders == null)
_textDecoders = new TextDecoder[byte.MaxValue];
object instance = Activator.CreateInstance(type);
TextDecoder textDecoder = (TextDecoder)instance;
foreach (EncodingTypeIdAttribute attribute in idAttributes)
{
logger.DebugFormat("Text Decoder 0x{0:X2} is {1}", attribute.Id, type.Name);
_textDecoders[attribute.Id] = textDecoder;
}
}
#region Scraper Storages
private Dictionary<int, DataStorageFactory> _dataStorages;
@ -668,5 +697,12 @@ namespace skyscraper5.Skyscraper.Plugins
propertyInfo.SetValue(targetObject, toSet);
}
}
public TextDecoder[] GetTextDecoders()
{
object clone = _textDecoders.Clone();
TextDecoder[] saneClone = (TextDecoder[])clone;
return saneClone;
}
}
}

View File

@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi;
using skyscraper5.Dvb.Psi.Model;
namespace skyscraper5.Skyscraper.Scraper
{
internal class FreesatTunnelScraper : IBatEventHandler, ISdtEventHandler, ITdtEventHandler, ITotEventHandler
{
private ushort? networkId;
private DateTime? currentDateTime;
public void OnBatBouquet(BatBouquet batBouquet)
{
}
public void OnBatTransportStream(BatBouquet batBouquet, BatTransportStream child)
{
}
public void OnSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService sdtService)
{
}
public void OnTdtTime(DateTime utcTime)
{
this.currentDateTime = utcTime;
}
public void OnTotTime(DateTime utcTime, LocalTimeOffsetDescriptor ltod)
{
this.currentDateTime = utcTime;
}
public void SetNetworkId(ushort networkId)
{
this.networkId = networkId;
}
public void SetTransportStreamId(ushort transportStreamId)
{
}
}
}

View File

@ -609,7 +609,11 @@ namespace skyscraper5.Skyscraper.Scraper
StreamTypeAutodetection sta = new StreamTypeAutodetection(mappingStream.ElementaryPid, this);
sta.ProgramContext.Program = result;
sta.ProgramContext.Stream = mappingStream;
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, sta);
sta.IntroduceStreamToContestants();
if (!sta.IsWinnerDetermined)
{
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, sta);
}
break;
case StreamType.IpMacNotification:
IntParser intParser = new IntParser(this);
@ -1633,8 +1637,7 @@ namespace skyscraper5.Skyscraper.Scraper
LogEvent(SkyscraperContextEvent.StationIdentification, stationIdentification);
}
}
private FreesatTunnelScraper freesatTunnel;
public void AutodetectionSucessful(int pid, Contestant contestant, ProgramContext programContext)
{
UiJunction?.NotifyStreamTypeDetection(contestant.Tag, pid);
@ -2036,6 +2039,17 @@ namespace skyscraper5.Skyscraper.Scraper
}
}
if (_pluginContexts != null)
{
foreach (object plugin in _pluginContexts)
{
IDisposable disposable = plugin as IDisposable;
if (disposable != null)
disposable.Dispose();
}
_pluginContexts.Clear();
}
DataStorage.WaitForCompletion();
}
@ -2671,5 +2685,18 @@ namespace skyscraper5.Skyscraper.Scraper
}
}
}
}
private List<object> _pluginContexts;
public List<object> PluginContext
{
get
{
if (_pluginContexts == null)
_pluginContexts = new List<object>();
return _pluginContexts;
}
}
}
}

View File

@ -35,5 +35,7 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection
}
public abstract void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext);
public abstract void Introduce(ProgramContext programContext);
}
}

View File

@ -33,5 +33,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new AitParser(skyscraperContext, programContext.ProgramNumber)));
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -1,19 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using skyscraper5.Dvb.Psi;
using skyscraper5.Dvb.Psi.Model;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper.Scraper.Utils;
namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
[SkyscraperPlugin]
class BatContestant : Contestant, IBatEventHandler, IDisposable
{
public BatContestant(int pid) : base("BAT", pid)
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
public BatContestant(int pid) : base("BAT", pid)
{
PacketProcessor = new PsiDecoder(pid, new BatParser(this));
}
@ -35,7 +39,13 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
throw new NotImplementedException();
logger.ErrorFormat("{0} {1} not yet implemented", nameof(BatContestant), nameof(DeclareWinner));
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder());
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -32,5 +32,9 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -107,7 +107,12 @@ 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)
public override void Introduce(ProgramContext programContext)
{
}
public void ProcessVirtualFilesystem(IFilesystem vfs, ProgramMappingStream pmtPid)
{
}
}

View File

@ -25,5 +25,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -51,5 +51,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new EitParser(skyscraperContext)));
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -25,6 +25,11 @@ namespace skyscraper5.src.Skyscraper.Scraper.StreamAutodetection.Contestants
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
}
public override void Dispose()
{
}

View File

@ -28,6 +28,11 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
}
public void OnIpMacNotification(int sourcePid, Platform platform, Target target, Operational operational)
{
Score++;

View File

@ -30,6 +30,11 @@ namespace skyscraper5.src.Skyscraper.Scraper.StreamAutodetection.Contestants
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
}
public override void Dispose()
{

View File

@ -30,6 +30,11 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new MultiprotocolEncapsulationDecoder(skyscraperContext)));
}
public override void Introduce(ProgramContext programContext)
{
}
public void OnIpv4PacketArrival(InternetHeader internetHeader, byte[] ipv4Packet)
{
Score++;

View File

@ -42,5 +42,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new NitParser(skyscraperContext)));
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -41,5 +41,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using skyscraper5.Dvb.Psi;
using skyscraper5.Dvb.Psi.Model;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
@ -41,13 +43,21 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
}
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
FreesatTunnelScraper fts = new FreesatTunnelScraper();
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new Pid0x11Decoder(fts, fts)));
//FreesatTunnelScraper fts = new FreesatTunnelScraper();
//skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new Pid0x11Decoder(fts, fts)));
logger.ErrorFormat("{0} {1} not yet implemented", nameof(Pid0x11Contestant), nameof(DeclareWinner));
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder());
}
public void SetNetworkId(ushort networkId)
public override void Introduce(ProgramContext programContext)
{
}
public void SetNetworkId(ushort networkId)
{
}

View File

@ -32,5 +32,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new PmtParser(skyscraperContext)));
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -57,5 +57,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -38,5 +38,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new Scte35SiDecoder(programContext.ProgramNumber, skyscraperContext)));
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -33,6 +33,11 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new SdtParser(skyscraperContext)));
}
public override void Introduce(ProgramContext programContext)
{
}
public void SetNetworkId(ushort networkId)
{
}

View File

@ -34,5 +34,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
pesDecoder.Tag = "subs";
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, pesDecoder);
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -28,6 +28,11 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new T2MIDecoder(pid, skyscraperContext));
}
public override void Introduce(ProgramContext programContext)
{
}
public void OnT2MiPacketLoss(int pid, byte expectedPacket, T2MIHeader header)
{
if (Score > 0)

View File

@ -54,7 +54,12 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PesDecoder(ttp));
}
public void OnMonochromeData(int networkId, int transportStreamId, ushort programNumber, MonochromeDataField result)
public override void Introduce(ProgramContext programContext)
{
}
public void OnMonochromeData(int networkId, int transportStreamId, ushort programNumber, MonochromeDataField result)
{
Score++;
}

View File

@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper.Utils;
namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
@ -33,10 +35,16 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
}
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
FreesatTunnelScraper fts = new FreesatTunnelScraper();
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new Pid0x11Decoder(fts, fts)));
}
logger.ErrorFormat("{0} {1} not yet implemented", nameof(TimeContestant), nameof(DeclareWinner));
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder());
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -37,5 +37,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new TsdtParser(skyscraperContext)));
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -34,5 +34,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
}
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2.Descriptors;
using skyscraper5.Mpeg2.Psi.Model;
namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection
@ -25,5 +26,16 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection
return null;
}
}
public UserDefinedDescriptor GetFirstUserDefinedDescriptor()
{
if (Stream == null)
return null;
if (Stream.UnknownUserDefines == null)
return null;
if (Stream.UnknownUserDefines.Count == 0)
return null;
return Stream.UnknownUserDefines[0];
}
}
}

View File

@ -1,17 +1,18 @@
using System;
using skyscraper5.Mpeg2;
using skyscraper5.Mpeg2.Psi;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.Mpeg2.Psi;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants;
namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection
{
@ -71,21 +72,30 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection
}
}
if (SomethingHappened())
{
Array.Sort(Scoreboard, (x, y) => y.Score.CompareTo(x.Score));
Contestant leader = Scoreboard[0];
Contestant runnerUp = Scoreboard[1];
long scoreDifference = leader.Score - runnerUp.Score;
if (scoreDifference > 5)
{
EventHandler.AutodetectionSucessful(Pid, leader, ProgramContext);
winnerDetermined = true;
Dispose();
}
}
CheckWinner();
}
private bool CheckWinner()
{
bool result = false;
if (SomethingHappened())
{
Array.Sort(Scoreboard, (x, y) => y.Score.CompareTo(x.Score));
Contestant leader = Scoreboard[0];
Contestant runnerUp = Scoreboard[1];
long scoreDifference = leader.Score - runnerUp.Score;
if (scoreDifference > 5)
{
EventHandler.AutodetectionSucessful(Pid, leader, ProgramContext);
winnerDetermined = true;
Dispose();
result = true;
}
}
return result;
}
private bool SomethingHappened()
{
foreach (Contestant contestant in Scoreboard)
@ -140,5 +150,36 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection
payloadUnitDecoder.PacketLoss();
}
}
public void IntroduceStreamToContestants()
{
foreach (Contestant contestant in Scoreboard)
{
contestant.Introduce(ProgramContext);
}
bool hasWinners = CheckWinner();
if (!hasWinners)
{
//No winners? How about losers?
for (int i = 0; i < Scoreboard.Length; i++)
{
if (Scoreboard[i].Score <= -10)
{
//Console.WriteLine("PID 0x{0:X4} is probably not for {1}", Pid, Scoreboard[i].GetType().Name);
EventHandler.AutodetectionRuleOut(Pid, Scoreboard[i], ProgramContext);
Scoreboard[i] = new DisqualifiedContestant(Scoreboard[i].Pid);
}
}
}
}
public bool IsWinnerDetermined
{
get
{
return winnerDetermined;
}
}
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Text;
using skyscraper5.Dvb;
using skyscraper5.Skyscraper.Plugins;
using skyscraper8.Skyscraper.Text;
namespace skyscraper5.Skyscraper.Text
{
@ -50,6 +52,7 @@ namespace skyscraper5.Skyscraper.Text
private static En300468AnnexATextDecoder _instance;
private static Encoding[] tables;
private static Encoding[] iso8859Mapping;
private static TextDecoder[] _textDecoders;
public static En300468AnnexATextDecoder GetInstance()
{
@ -104,14 +107,14 @@ namespace skyscraper5.Skyscraper.Text
else if (buffer[0] == 0x1f)
{
//It shall be coded according to ETSI TS 101 162
switch (buffer[1])
if (_textDecoders == null)
_textDecoders = PluginManager.GetInstance().GetTextDecoders();
TextDecoder matchingTextDecoder = _textDecoders[buffer[1]];
if (matchingTextDecoder == null)
{
case 0x01: //BBC, undocumented - but their Freesat Patch might help: https://www.rst38.org.uk/vdr/
case 0x02:
return null;
default:
throw new NotImplementedException(String.Format("Encoding type ID 0x{0:X2}", buffer[1]));
throw new TextException(String.Format("No decoder for Encoding type ID 0x{0:X2}", buffer[1]));
}
return matchingTextDecoder.Decode(buffer);
}
else if (buffer[0] >= 0x16 && buffer[0] <= 0x1e)
{

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.Skyscraper.Text
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class EncodingTypeIdAttribute : Attribute
{
public byte Id { get; }
public EncodingTypeIdAttribute(byte id)
{
Id = id;
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.Skyscraper.Text
{
public interface TextDecoder
{
string Decode(byte[] buffer);
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.Skyscraper.Text
{
public class TextException : SkyscraperCoreException
{
public TextException()
{
}
public TextException(string message) : base(message)
{
}
public TextException(string message, Exception inner) : base(message, inner)
{
}
}
}