mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-01-19 05:42:03 +01:00
- added experimental support for Loewe / Hisense 2017 servicelist.db
file format - show error message when trying to open a .zip file that doen't contain the expected files of a Samsung J series or Toshiba .zip channel list - show error message when trying to open a broken .zip file, which is most likely caused by exporting to a USB stick formatted with NTFS - allow changing the "crypt" flag for Samsung .scm lists - iterating through loaders supporting a file extension till one can read the file
This commit is contained in:
@@ -351,6 +351,8 @@ namespace ChanSort.Api
|
||||
this.unsortedChannelMode = mode;
|
||||
foreach (var list in DataRoot.ChannelLists)
|
||||
{
|
||||
if (list.IsMixedSourceFavoritesList)
|
||||
continue;
|
||||
var sortedChannels = list.Channels.OrderBy(ChanSortCriteria).ToList();
|
||||
int maxProgNr = 0;
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace ChanSort.Api
|
||||
public int ProgramNrPreset { get; set; }
|
||||
|
||||
public bool IsNameModified { get; set; }
|
||||
public bool IsProxy => this.RecordIndex < 0;
|
||||
|
||||
#region ctor()
|
||||
protected ChannelInfo()
|
||||
|
||||
@@ -30,6 +30,11 @@ namespace ChanSort.Api
|
||||
public int MaxChannelNameLength { get; set; }
|
||||
public int PresetProgramNrCount { get; private set; }
|
||||
public IList<string> VisibleColumnFieldNames;
|
||||
|
||||
/// <summary>
|
||||
/// Set for helper lists used to manage favorites mixed from all input sources.
|
||||
/// When true, the UI won't show the "Pr#" tab but will show "Fav A-D" tabs and a "Source" column.
|
||||
/// </summary>
|
||||
public bool IsMixedSourceFavoritesList { get; set; }
|
||||
|
||||
#region Caption
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace ChanSort.Api
|
||||
public bool SortedFavorites { get; set; }
|
||||
public bool MixedSourceFavorites { get; set; }
|
||||
public bool AllowGapsInFavNumbers { get; set; }
|
||||
public bool ShowDeletedChannels { get; set; }
|
||||
|
||||
public DataRoot()
|
||||
{
|
||||
@@ -105,10 +106,20 @@ namespace ChanSort.Api
|
||||
#region ApplyCurrentProgramNumbers()
|
||||
public void ApplyCurrentProgramNumbers()
|
||||
{
|
||||
int c = 0;
|
||||
if (this.MixedSourceFavorites || this.SortedFavorites)
|
||||
{
|
||||
for (int m = (int) this.SupportedFavorites; m != 0; m >>= 1)
|
||||
++c;
|
||||
}
|
||||
|
||||
foreach (var list in this.ChannelLists)
|
||||
{
|
||||
foreach (var channel in list.Channels)
|
||||
channel.NewProgramNr = channel.OldProgramNr;
|
||||
{
|
||||
for (int i=0; i<=c; i++)
|
||||
channel.SetPosition(i, channel.GetOldPosition(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -58,7 +58,9 @@ namespace ChanSort.Api
|
||||
TivuSatD = Digital + Sat + TivuSat,
|
||||
CanalDigitalSatD = Digital + Sat + CanalDigital,
|
||||
DigitalPlusD = Digital + Sat + DigitalPlus,
|
||||
CyfraPlusD = Digital + Sat + CyfraPlus
|
||||
CyfraPlusD = Digital + Sat + CyfraPlus,
|
||||
|
||||
All = MaskAnalogDigital | MaskAntennaCableSat | MaskTvRadio
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -6,11 +6,10 @@ namespace ChanSort.Api
|
||||
{
|
||||
public static class Tools
|
||||
{
|
||||
public static V TryGet<K, V>(this IDictionary<K, V> dict, K key)
|
||||
public static V TryGet<K, V>(this IDictionary<K, V> dict, K key, V defaultValue = default(V))
|
||||
{
|
||||
V val;
|
||||
dict.TryGetValue(key, out val);
|
||||
return val;
|
||||
return dict.TryGetValue(key, out val) ? val : defaultValue;
|
||||
}
|
||||
|
||||
#region GetAnalogChannelNumber()
|
||||
|
||||
@@ -151,6 +151,10 @@ namespace ChanSort.Loader.Hisense
|
||||
{
|
||||
this.RepairCorruptedDatabaseImage(cmd);
|
||||
this.LoadTableNames(cmd);
|
||||
|
||||
if (!tableNames.Contains("svl_1") && !tableNames.Contains("svl_2") && !tableNames.Contains("svl_3"))
|
||||
throw new FileLoadException("File doesn't contain svl_* tables");
|
||||
|
||||
this.LoadSatelliteData(cmd);
|
||||
this.LoadTslData(cmd);
|
||||
this.LoadSvlData(cmd);
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
#define HISENSE_ENABLED
|
||||
|
||||
/*
|
||||
Support for the Hisense file format (Sep 2015) is currently disabled due to the risk of damaging the TV when
|
||||
users import files in an older/newer format than the currently installed firmware expects.
|
||||
*/
|
||||
|
||||
using ChanSort.Api;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Hisense
|
||||
{
|
||||
#if HISENSE_ENABLED
|
||||
public class HisDbSerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string PluginName => "Hisense channel.db";
|
||||
public string FileFilter => "channel*.db";
|
||||
public string FileFilter => "*.db";
|
||||
|
||||
#region CreateSerializer()
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
return new HisDbSerializer(inputFile);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,78 @@
|
||||
//#define LOCK_LCN_LISTS
|
||||
#define LOCK_LCN_LISTS
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SQLite;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Hisense
|
||||
namespace ChanSort.Loader.Hisense2017
|
||||
{
|
||||
public class HisDbSerializer : SerializerBase
|
||||
{
|
||||
private readonly Dictionary<long, ChannelInfo> channelsById = new Dictionary<long, ChannelInfo>();
|
||||
private readonly Dictionary<int, ChannelList> channelLists = new Dictionary<int, ChannelList>();
|
||||
private ChannelList favlist;
|
||||
private readonly Dictionary<int,int> favListIdToFavIndex = new Dictionary<int, int>();
|
||||
private List<string> tableNames;
|
||||
/*
|
||||
* The 2017 Hisense / Loewe data model for channel lists is a bit different than all other supported models and need some workarounds to be supported.
|
||||
* It is based on a flat "Services" table which doesn't hold program numbers and a FavoritesList/FavoritesItem table to assign numbers
|
||||
* to physical tuner lists and user favorite lists alike.
|
||||
*
|
||||
* Physical channel lists (e.g. for $av, Astra, Hot Bird) have their own ChannelList in the channelList dictionary and use
|
||||
* ChannelInfo.NewProgramNr to hold the program number. This doesn't allow the user to add services from other lists.
|
||||
*
|
||||
* The user favorite lists (FAV1-FAV4) use the separate favList ChannelList filled with all services from all physical lists.
|
||||
* ChannelInfo.FavIndex[0-3] holds the information for the program numbers in FAV1-4. The value -1 is used to indicate "not included".
|
||||
*
|
||||
* The $all list is hidden from the user and automatically updated to match the contents of all other lists (except $av and FAV1-4).
|
||||
*
|
||||
* The $av list is hidden from the user and not updated at all.
|
||||
*
|
||||
* This loader poses the following restrictions on the database:
|
||||
* - a service must not appear in more than one physical channel list ($all and FAV1-4 are not part of this restriction)
|
||||
* - a service can't appear more than once in any list
|
||||
*
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// list of all table names in the database
|
||||
/// </summary>
|
||||
private readonly List<string> tableNames = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// mapping of Service.Pid => ChannelInfo
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, ChannelInfo> channelsById = new Dictionary<long, ChannelInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// mapping of FavoriteList.Pid => ChannelList.
|
||||
/// This dict does not include real user favorite lists (FAV1-FAV4).
|
||||
/// </summary>
|
||||
private readonly Dictionary<int, ChannelList> channelLists = new Dictionary<int, ChannelList>();
|
||||
|
||||
/// <summary>
|
||||
/// This list is filled with all channels/services and serves as a holder for favorite lists 1-4
|
||||
/// </summary>
|
||||
private readonly ChannelList userFavList = new ChannelList(SignalSource.All, "Favorites");
|
||||
|
||||
/// <summary>
|
||||
/// mapping of FavoriteList.Pid for FAV1-4 => index of the internal favorite list within userFavList (0-3)
|
||||
/// Pids that don't belong to the FAV1-4 are not included in this dictionary.
|
||||
/// </summary>
|
||||
private readonly Dictionary<int,int> favListIdToFavIndex = new Dictionary<int, int>();
|
||||
|
||||
/// <summary>
|
||||
/// FavoriteList.Pid of the $all list
|
||||
/// </summary>
|
||||
private int pidAll;
|
||||
|
||||
/// <summary>
|
||||
/// FavoriteList.Pid of the $av list
|
||||
/// </summary>
|
||||
private int pidAv;
|
||||
|
||||
/// <summary>
|
||||
/// Fields of the ChannelInfo that will be shown in the UI
|
||||
/// </summary>
|
||||
private static readonly List<string> ColumnNames = new List<string>
|
||||
{
|
||||
"OldPosition",
|
||||
@@ -28,6 +82,7 @@ namespace ChanSort.Loader.Hisense
|
||||
"Name",
|
||||
"ShortName",
|
||||
"Favorites",
|
||||
"Skip",
|
||||
"Lock",
|
||||
"Hidden",
|
||||
"Encrypted",
|
||||
@@ -38,10 +93,14 @@ namespace ChanSort.Loader.Hisense
|
||||
"ServiceType",
|
||||
"ServiceTypeName",
|
||||
"NetworkName",
|
||||
"Satellite",
|
||||
"SymbolRate"
|
||||
"Satellite"
|
||||
// "SymbolRate"
|
||||
};
|
||||
|
||||
#region class HisTransponder
|
||||
/// <summary>
|
||||
/// This class holds information from the Tuner table
|
||||
/// </summary>
|
||||
public class HisTransponder : Transponder
|
||||
{
|
||||
public SignalSource SignalSource { get; set; }
|
||||
@@ -51,6 +110,7 @@ namespace ChanSort.Loader.Hisense
|
||||
{
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ctor()
|
||||
|
||||
@@ -59,10 +119,12 @@ namespace ChanSort.Loader.Hisense
|
||||
DepencencyChecker.AssertVc2010RedistPackageX86Installed();
|
||||
|
||||
Features.ChannelNameEdit = ChannelNameEditMode.All;
|
||||
Features.CanDeleteChannels = false;
|
||||
Features.CanSkipChannels = false;
|
||||
Features.CanDeleteChannels = true;
|
||||
Features.CanSkipChannels = true;
|
||||
Features.CanHaveGaps = true;
|
||||
DataRoot.MixedSourceFavorites = true;
|
||||
DataRoot.SortedFavorites = true;
|
||||
DataRoot.ShowDeletedChannels = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -79,9 +141,13 @@ namespace ChanSort.Loader.Hisense
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
RepairCorruptedDatabaseImage(cmd);
|
||||
LoadLists(cmd);
|
||||
LoadTableNames(cmd);
|
||||
LoadSatelliteData(cmd);
|
||||
|
||||
// make sure this .db file contains the required tables
|
||||
if (!tableNames.Contains("service") || !tableNames.Contains("tuner") || !tableNames.Contains("favoriteitem"))
|
||||
throw new FileLoadException("File doesn't contain service/tuner/favoriteitem tables");
|
||||
|
||||
LoadLists(cmd);
|
||||
LoadTunerData(cmd);
|
||||
LoadServiceData(cmd);
|
||||
LoadFavorites(cmd);
|
||||
@@ -108,7 +174,6 @@ namespace ChanSort.Loader.Hisense
|
||||
|
||||
private void LoadTableNames(SQLiteCommand cmd)
|
||||
{
|
||||
tableNames = new List<string>();
|
||||
cmd.CommandText = "SELECT name FROM sqlite_master WHERE type = 'table' order by name";
|
||||
using (var r = cmd.ExecuteReader())
|
||||
{
|
||||
@@ -129,62 +194,37 @@ namespace ChanSort.Loader.Hisense
|
||||
{
|
||||
int listId = r.GetInt32(0);
|
||||
string name = r.GetString(1);
|
||||
if (name.StartsWith("FAV"))
|
||||
|
||||
if (name == "$all")
|
||||
pidAll = listId;
|
||||
else if (name == "$av")
|
||||
pidAv = listId;
|
||||
else if (name.StartsWith("FAV"))
|
||||
{
|
||||
favListIdToFavIndex.Add(listId, int.Parse(name.Substring(3)));
|
||||
// all real user favorite lists are using the "userFavList"
|
||||
favListIdToFavIndex.Add(listId, int.Parse(name.Substring(3)) - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
var list = new ChannelList(SignalSource.Analog | SignalSource.AvInput | SignalSource.DvbCT | SignalSource.DvbS | SignalSource.TvAndRadio, name);
|
||||
// lists for physical channel sources
|
||||
var list = new ChannelList(SignalSource.All, name);
|
||||
list.VisibleColumnFieldNames = ColumnNames;
|
||||
list.IsMixedSourceFavoritesList = list.Caption.StartsWith("FAV");
|
||||
|
||||
channelLists.Add(listId, list);
|
||||
DataRoot.AddChannelList(list);
|
||||
}
|
||||
|
||||
|
||||
favlist = new ChannelList(SignalSource.Analog | SignalSource.AvInput | SignalSource.DvbCT | SignalSource.DvbS | SignalSource.TvAndRadio, "Favorites");
|
||||
favlist.VisibleColumnFieldNames = ColumnNames;
|
||||
favlist.IsMixedSourceFavoritesList = true;
|
||||
channelLists.Add(0, favlist);
|
||||
DataRoot.AddChannelList(favlist);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region LoadSatelliteData()
|
||||
|
||||
|
||||
private void LoadSatelliteData(SQLiteCommand cmd)
|
||||
{
|
||||
// sample data file doesn't contain any satellite information
|
||||
#if false
|
||||
var regex = new Regex(@"^satellite$");
|
||||
foreach (var tableName in this.tableNames)
|
||||
{
|
||||
if (!regex.IsMatch(tableName))
|
||||
continue;
|
||||
cmd.CommandText = "select satl_rec_id, i2_orb_pos, ac_sat_name from " + tableName;
|
||||
using (var r = cmd.ExecuteReader())
|
||||
{
|
||||
while (r.Read())
|
||||
{
|
||||
var sat = new Satellite(r.GetInt32(0));
|
||||
var pos = r.GetInt32(1);
|
||||
sat.OrbitalPosition = $"{(decimal) Math.Abs(pos)/10:n1}{(pos < 0 ? 'W' : 'E')}";
|
||||
sat.Name = r.GetString(2);
|
||||
this.DataRoot.AddSatellite(sat);
|
||||
}
|
||||
if (name.StartsWith("$"))
|
||||
list.ReadOnly = true;
|
||||
else
|
||||
DataRoot.AddChannelList(list); // only lists in the DataRoot will be visible in the UI
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// add the special list for the user favorites 1-4
|
||||
userFavList.VisibleColumnFieldNames = ColumnNames;
|
||||
userFavList.IsMixedSourceFavoritesList = true;
|
||||
channelLists.Add(0, userFavList);
|
||||
DataRoot.AddChannelList(userFavList);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region LoadTunerData()
|
||||
|
||||
private void LoadTunerData(SQLiteCommand cmd)
|
||||
@@ -198,6 +238,7 @@ namespace ChanSort.Loader.Hisense
|
||||
Tuple.Create("T", SignalSource.DvbT, "bandwidth"),
|
||||
Tuple.Create("T2", SignalSource.DvbT, "bandwidth"),
|
||||
};
|
||||
|
||||
foreach (var input in inputs)
|
||||
{
|
||||
var table = input.Item1;
|
||||
@@ -210,28 +251,6 @@ namespace ChanSort.Loader.Hisense
|
||||
t.SymbolRate = r.GetInt32(i0 + 1);
|
||||
});
|
||||
}
|
||||
|
||||
#if false
|
||||
this.LoadTunerData(cmd, "tsl_#_data_sat_dig", ", freq, sym_rate, orb_pos", (t, r, i0) =>
|
||||
{
|
||||
t.FrequencyInMhz = r.GetInt32(i0 + 0);
|
||||
t.SymbolRate = r.GetInt32(i0 + 1);
|
||||
|
||||
// satellite information may or may not be available in the database. if there is none, create a proxy sat records from the orbital position in the TSL data
|
||||
if (t.Satellite == null)
|
||||
{
|
||||
var opos = r.GetInt32(i0 + 2);
|
||||
var sat = this.DataRoot.Satellites.TryGet(opos);
|
||||
if (sat == null)
|
||||
{
|
||||
sat = new Satellite(opos);
|
||||
var pos = (decimal) opos / 10;
|
||||
sat.Name = pos < 0 ? (-pos).ToString("n1") + "W" : pos.ToString("n1") + "E";
|
||||
}
|
||||
t.Satellite = sat;
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
private void LoadTunerData(SQLiteCommand cmd, string joinTable, string joinFields, Action<HisTransponder, SQLiteDataReader, int> enhanceTransponderInfo)
|
||||
@@ -266,7 +285,7 @@ namespace ChanSort.Loader.Hisense
|
||||
private void LoadServiceData(SQLiteCommand cmd)
|
||||
{
|
||||
cmd.CommandText = @"
|
||||
select s.pid, s.type, anls.Frequency, digs.TunerId, digs.Sid, Name, ShortName, Encrypted, Visible, Selectable, ParentalLock
|
||||
select s.pid, s.type, anls.Frequency, digs.TunerId, digs.Sid, Name, ShortName, Encrypted, Visible, Selectable, ParentalLock, MediaType
|
||||
from service s
|
||||
left outer join AnalogService anls on anls.ServiceId=s.Pid
|
||||
left outer join DVBService digs on digs.ServiceId=s.Pid
|
||||
@@ -277,11 +296,11 @@ left outer join DVBService digs on digs.ServiceId=s.Pid
|
||||
while (r.Read())
|
||||
{
|
||||
ChannelInfo ci = null;
|
||||
if (!r.IsDBNull(2))
|
||||
if (!r.IsDBNull(2)) // AnalogService
|
||||
ci = new ChannelInfo(SignalSource.Analog, r.GetInt32(0), -1, r.GetString(5));
|
||||
else if (!r.IsDBNull(3))
|
||||
else if (!r.IsDBNull(3)) // DvbService
|
||||
{
|
||||
var trans = (HisTransponder)DataRoot.Transponder.TryGet(r.GetInt32(3));
|
||||
var trans = (HisTransponder) DataRoot.Transponder.TryGet(r.GetInt32(3));
|
||||
ci = new ChannelInfo(trans.SignalSource, r.GetInt32(0), -1, r.GetString(5));
|
||||
ci.Transponder = trans;
|
||||
ci.FreqInMhz = trans.FrequencyInMhz;
|
||||
@@ -294,113 +313,89 @@ left outer join DVBService digs on digs.ServiceId=s.Pid
|
||||
ci.Hidden = r.GetInt32(8) == 0;
|
||||
ci.Skip = r.GetInt32(9) == 0;
|
||||
ci.Lock = r.GetInt32(10) != 0;
|
||||
var mediaType = r.GetInt32(11);
|
||||
if (mediaType == 1)
|
||||
{
|
||||
ci.SignalSource |= SignalSource.Tv;
|
||||
ci.ServiceTypeName = "TV";
|
||||
}
|
||||
else if (mediaType == 2)
|
||||
{
|
||||
ci.SignalSource |= SignalSource.Radio;
|
||||
ci.ServiceTypeName = "Radio";
|
||||
}
|
||||
else
|
||||
ci.ServiceTypeName = mediaType.ToString();
|
||||
}
|
||||
else if (r.GetInt32(1) == 0)
|
||||
else if (r.GetInt32(1) == 0) // A/V input
|
||||
{
|
||||
ci = new ChannelInfo(SignalSource.AvInput, r.GetInt32(0), -1, r.GetString(5));
|
||||
ci.ServiceTypeName = "A/V";
|
||||
}
|
||||
|
||||
if (ci != null)
|
||||
channelsById.Add(ci.RecordIndex, ci);
|
||||
}
|
||||
}
|
||||
#if LOCK_LCN_LISTS
|
||||
// make the current list read-only if LCN is used
|
||||
if (r.GetInt32(i0 + 3) != 0)
|
||||
{
|
||||
this.channelLists[x - 1].ReadOnly = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#if false
|
||||
private void LoadServiceData(SQLiteCommand cmd, string joinTable, string joinFields, Action<ChannelInfo, SQLiteDataReader, int> enhanceChannelInfo)
|
||||
{
|
||||
if (!tableNames.Contains(joinTable))
|
||||
return;
|
||||
|
||||
cmd.CommandText = $"select service.pid, -1, {joinFields}"
|
||||
+ $" from service inner join {joinTable} on {joinTable}.ServiceId=";
|
||||
using (var r = cmd.ExecuteReader())
|
||||
{
|
||||
while (r.Read())
|
||||
{
|
||||
var id = (uint)r.GetInt32(0);
|
||||
var prNr = (int)(uint)r.GetInt32(1) >> 18;
|
||||
var trans = DataRoot.Transponder.TryGet((r.GetInt32(2) << 16) | r.GetInt32(3));
|
||||
var stype = (ServiceType)r.GetInt32(4);
|
||||
var name = r.GetString(5);
|
||||
var nwMask = (NwMask)r.GetInt32(6);
|
||||
var sid = r.GetInt32(7);
|
||||
var bmedium = (BroadcastMedium)r.GetInt32(8);
|
||||
|
||||
var ssource = DetermineSignalSource(bmedium, stype);
|
||||
var ci = new ChannelInfo(ssource, id, prNr, name);
|
||||
if (trans != null)
|
||||
{
|
||||
ci.Transponder = trans;
|
||||
ci.OriginalNetworkId = trans.OriginalNetworkId;
|
||||
ci.TransportStreamId = trans.TransportStreamId;
|
||||
ci.SymbolRate = trans.SymbolRate;
|
||||
ci.FreqInMhz = trans.FrequencyInMhz;
|
||||
ci.Satellite = trans.Satellite?.ToString();
|
||||
}
|
||||
|
||||
ci.ServiceId = sid;
|
||||
|
||||
//ci.Skip = (nwMask & NwMask.Active) == 0;
|
||||
ci.Lock = (nwMask & NwMask.Lock) != 0;
|
||||
ci.Hidden = (nwMask & NwMask.Visible) == 0;
|
||||
ci.Favorites |= (Favorites)((int)(nwMask & (NwMask.Fav1 | NwMask.Fav2 | NwMask.Fav3 | NwMask.Fav4)) >> 4);
|
||||
|
||||
if (stype == ServiceType.Radio)
|
||||
ci.ServiceTypeName = "Radio";
|
||||
else if (stype == ServiceType.Tv)
|
||||
ci.ServiceTypeName = "TV";
|
||||
else if (stype == ServiceType.App)
|
||||
ci.ServiceTypeName = "Data";
|
||||
|
||||
enhanceChannelInfo(ci, r, 9);
|
||||
|
||||
var list = channelLists[tableNr - 1];
|
||||
ci.Source = list.ShortCaption;
|
||||
DataRoot.AddChannel(list, ci);
|
||||
|
||||
// add the channel to all favorites lists
|
||||
DataRoot.AddChannel(channelLists[6], ci);
|
||||
channelsById[ci.RecordIndex] = ci;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region LoadFavorites()
|
||||
|
||||
private void LoadFavorites(SQLiteCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "select FavoriteId, ServiceId, ChannelNum from FavoriteItem fi";
|
||||
cmd.CommandText = @"
|
||||
select fi.FavoriteId, fi.ServiceId, fi.ChannelNum, fi.Selectable, fi.Visible, fi.isDeleted, fi.Protected, l.Lcn
|
||||
from FavoriteItem fi
|
||||
left outer join Lcn l on l.ServiceId=fi.ServiceId and l.FavoriteId=fi.FavoriteId
|
||||
";
|
||||
using (var r = cmd.ExecuteReader())
|
||||
{
|
||||
while (r.Read())
|
||||
{
|
||||
int favListId = r.GetInt32(0);
|
||||
var ci = channelsById.TryGet(r.GetInt32(1));
|
||||
int favListIdx = favListIdToFavIndex.TryGet(favListId);
|
||||
if (favListIdx != 0)
|
||||
if (ci == null)
|
||||
continue;
|
||||
|
||||
int favListIdx = favListIdToFavIndex.TryGet(favListId, -1);
|
||||
if (favListIdx >= 0)
|
||||
{
|
||||
ci?.SetOldPosition(favListIdx, r.GetInt32(1));
|
||||
// NOTE: we need to set the NEW fav index here because AddChannel will use the new value to initialize the old value
|
||||
ci.FavIndex[favListIdx] = r.GetInt32(2);
|
||||
}
|
||||
else
|
||||
|
||||
ci.SetOldPosition(favListIdx + 1, r.GetInt32(2)); // 0=main nr, 1-4=fav 1-4
|
||||
if (favListIdx < 0)
|
||||
{
|
||||
// physical channel list (specific satellite, $av, ...)
|
||||
var list = channelLists.TryGet(favListId);
|
||||
// TODO create copy of channel for each channel list so that it can have an independant number
|
||||
ci?.SetOldPosition(0, r.GetInt32(1));
|
||||
|
||||
if (!r.IsDBNull(7)) // LCN
|
||||
{
|
||||
ci.ProgramNrPreset = r.GetInt32(7);
|
||||
#if LOCK_LCN_LISTS
|
||||
list.ReadOnly = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
ci.Skip = r.GetInt32(3) == 0;
|
||||
ci.Lock = r.GetInt32(6) != 0;
|
||||
ci.Hidden = r.GetInt32(4) == 0;
|
||||
ci.IsDeleted = r.GetInt32(5) != 0;
|
||||
ci.Source = list.ShortCaption;
|
||||
if (ci.IsDeleted)
|
||||
ci.OldProgramNr = -1;
|
||||
if ((ci.SignalSource & (SignalSource.MaskAntennaCableSat | SignalSource.MaskAnalogDigital)) == SignalSource.DvbS)
|
||||
ci.Satellite = list.ShortCaption;
|
||||
|
||||
DataRoot.AddChannel(list, ci);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var ci in channelsById.Values)
|
||||
DataRoot.AddChannel(favlist, ci);
|
||||
DataRoot.AddChannel(userFavList, ci);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -410,8 +405,6 @@ left outer join DVBService digs on digs.ServiceId=s.Pid
|
||||
|
||||
public override void Save(string tvOutputFile)
|
||||
{
|
||||
//Editor.SequentializeFavPos(channelLists[6], 4);
|
||||
|
||||
if (tvOutputFile != FileName)
|
||||
File.Copy(FileName, tvOutputFile, true);
|
||||
|
||||
@@ -424,17 +417,13 @@ left outer join DVBService digs on digs.ServiceId=s.Pid
|
||||
cmd.Transaction = trans;
|
||||
try
|
||||
{
|
||||
CreateFavTables(cmd);
|
||||
#if !LOCK_LCN_LISTS
|
||||
ResetLcn(cmd);
|
||||
#endif
|
||||
foreach (var list in DataRoot.ChannelLists)
|
||||
{
|
||||
if (list.ReadOnly)
|
||||
continue;
|
||||
foreach (var ci in list.Channels)
|
||||
UpdateChannel(cmd, ci);
|
||||
}
|
||||
UpdateServices(cmd);
|
||||
UpdatePhysicalChannelLists(cmd);
|
||||
UpdateUserFavoriteLists(cmd);
|
||||
|
||||
trans.Commit();
|
||||
FileName = tvOutputFile;
|
||||
}
|
||||
@@ -446,165 +435,134 @@ left outer join DVBService digs on digs.ServiceId=s.Pid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateFavTables()
|
||||
|
||||
private void CreateFavTables(SQLiteCommand cmd)
|
||||
{
|
||||
for (var i = 1; i <= 4; i++)
|
||||
if (!tableNames.Contains("fav_" + i))
|
||||
{
|
||||
cmd.CommandText = $"CREATE TABLE fav_{i} (ui2_svc_id INTEGER, ui2_svc_rec_id INTEGER, user_defined_ch_num VARCHAR, user_defined_ch_name VARCHAR)";
|
||||
cmd.ExecuteNonQuery();
|
||||
tableNames.Add($"fav_{i}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ResetLcn()
|
||||
|
||||
private void ResetLcn(SQLiteCommand cmd)
|
||||
{
|
||||
var regex = new Regex(@"^svl_\d_data_dvb$");
|
||||
foreach (var table in tableNames)
|
||||
cmd.CommandText = "delete from Lcn where FavoriteId<>" + pidAv;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UpdateServices()
|
||||
private void UpdateServices(SQLiteCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "update Service set Name=@name, ShortName=@sname, ParentalLock=@lock, Visible=@vis, Selectable=@sel, FavTag=@fav1, FavTag2=@fav1, FavTag3=@fav3, FavTag4=@fav4 where Pid=@servId";
|
||||
cmd.Parameters.Clear();
|
||||
cmd.Parameters.Add("@servId", DbType.Int32);
|
||||
cmd.Parameters.Add("@name", DbType.String);
|
||||
cmd.Parameters.Add("@sname", DbType.String);
|
||||
cmd.Parameters.Add("@lock", DbType.Int32);
|
||||
cmd.Parameters.Add("@vis", DbType.Int32);
|
||||
cmd.Parameters.Add("@sel", DbType.Int32);
|
||||
cmd.Parameters.Add("@fav1", DbType.Int32);
|
||||
cmd.Parameters.Add("@fav2", DbType.Int32);
|
||||
cmd.Parameters.Add("@fav3", DbType.Int32);
|
||||
cmd.Parameters.Add("@fav4", DbType.Int32);
|
||||
cmd.Prepare();
|
||||
|
||||
foreach (var ci in channelsById.Values)
|
||||
{
|
||||
if (!regex.IsMatch(table))
|
||||
continue;
|
||||
cmd.CommandText = "update " + table + " set cur_lcn=0, original_lcn=0, lcn_idx=0";
|
||||
cmd.Parameters["@servId"].Value = ci.RecordIndex;
|
||||
cmd.Parameters["@name"].Value = ci.Name;
|
||||
cmd.Parameters["@sname"].Value = ci.ShortName;
|
||||
cmd.Parameters["@lock"].Value = ci.Lock ? 1 : 0;
|
||||
cmd.Parameters["@vis"].Value = ci.Hidden ? 0 : 1;
|
||||
cmd.Parameters["@sel"].Value = ci.Skip ? 0 : 1;
|
||||
cmd.Parameters["@fav1"].Value = (ci.Favorites & Favorites.A) != 0 ? 1 : 0;
|
||||
cmd.Parameters["@fav2"].Value = (ci.Favorites & Favorites.B) != 0 ? 1 : 0;
|
||||
cmd.Parameters["@fav3"].Value = (ci.Favorites & Favorites.C) != 0 ? 1 : 0;
|
||||
cmd.Parameters["@fav4"].Value = (ci.Favorites & Favorites.D) != 0 ? 1 : 0;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UpdateChannel()
|
||||
|
||||
private void UpdateChannel(SQLiteCommand cmd, ChannelInfo ci)
|
||||
#region UpdatePhysicalChannelLists()
|
||||
private void UpdatePhysicalChannelLists(SQLiteCommand cmd)
|
||||
{
|
||||
if (ci.RecordIndex < 0) // skip reference list proxy channels
|
||||
return;
|
||||
|
||||
var x = (int) ((ulong) ci.RecordIndex >> 32); // the table number is kept in the higher 32 bits
|
||||
var id = (int) (ci.RecordIndex & 0xFFFFFFFF); // the record id is kept in the lower 32 bits
|
||||
|
||||
var resetFlags = NwMask.Fav1 | NwMask.Fav2 | NwMask.Fav3 | NwMask.Fav4 | NwMask.Lock | NwMask.Visible;
|
||||
var setFlags = (NwMask) (((int) ci.Favorites & 0x0F) << 4);
|
||||
if (ci.Lock) setFlags |= NwMask.Lock;
|
||||
if (!ci.Hidden && ci.NewProgramNr >= 0) setFlags |= NwMask.Visible;
|
||||
|
||||
cmd.CommandText = $"update svl_{x} set channel_id=(channel_id&{0x3FFFF})|(@chnr << 18)" +
|
||||
$", ch_id_txt=@chnr || ' 0'" +
|
||||
$", ac_name=@name" +
|
||||
$", option_mask=option_mask|{(int) (OptionMask.ChNumEdited | OptionMask.NameEdited)}" +
|
||||
$", nw_mask=(nw_mask&@resetFlags)|@setFlags" +
|
||||
$" where svl_rec_id=@id";
|
||||
cmd.CommandText = "update FavoriteItem set ChannelNum=@ch, isDeleted=@del, Protected=@prot, Selectable=@sel, Visible=@vis where FavoriteId=@favId and ServiceId=@servId";
|
||||
cmd.Parameters.Clear();
|
||||
cmd.Parameters.Add("@id", DbType.Int32);
|
||||
cmd.Parameters.Add("@chnr", DbType.Int32);
|
||||
cmd.Parameters.Add("@name", DbType.String);
|
||||
cmd.Parameters.Add("@resetFlags", DbType.Int32);
|
||||
cmd.Parameters.Add("@setFlags", DbType.Int32);
|
||||
cmd.Parameters["@id"].Value = id;
|
||||
cmd.Parameters["@chnr"].Value = ci.NewProgramNr;
|
||||
cmd.Parameters["@name"].Value = ci.Name;
|
||||
cmd.Parameters["@resetFlags"].Value = ~(int) resetFlags;
|
||||
cmd.Parameters["@setFlags"].Value = (int) setFlags;
|
||||
cmd.ExecuteNonQuery();
|
||||
cmd.Parameters.Add("@favId", DbType.Int32);
|
||||
cmd.Parameters.Add("@servId", DbType.Int32);
|
||||
cmd.Parameters.Add("@ch", DbType.Int32);
|
||||
cmd.Parameters.Add("@del", DbType.Int32);
|
||||
cmd.Parameters.Add("@prot", DbType.Int32);
|
||||
cmd.Parameters.Add("@sel", DbType.Int32);
|
||||
cmd.Parameters.Add("@vis", DbType.Int32);
|
||||
cmd.Prepare();
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
if (ci.FavIndex[i] <= 0)
|
||||
foreach (var entry in channelLists)
|
||||
{
|
||||
var list = entry.Value;
|
||||
if (list.ReadOnly) // don't update read-only lists (i.e. containing LCNs)
|
||||
continue;
|
||||
|
||||
// don't update the $all list directly. It will be updated while iterating all other lists
|
||||
var favId = entry.Key;
|
||||
if (favId == pidAll)
|
||||
continue;
|
||||
|
||||
foreach (var ci in list.Channels)
|
||||
{
|
||||
cmd.CommandText = $"delete from fav_{i + 1} where ui2_svc_id={ci.RecordIndex >> 32} and ui2_svc_rec_id={ci.RecordIndex & 0xFFFF}";
|
||||
if (ci.IsProxy) // ignore proxies for missing channels that might have been added by applying a reference list
|
||||
continue;
|
||||
|
||||
cmd.Parameters["@favId"].Value = favId;
|
||||
cmd.Parameters["@servId"].Value = ci.RecordIndex;
|
||||
cmd.Parameters["@ch"].Value = ci.NewProgramNr <= 0 ? 9999 : ci.NewProgramNr;
|
||||
cmd.Parameters["@del"].Value = ci.NewProgramNr <= 0 ? 1 : 0; // 1 or -1 ?
|
||||
// not sure if the following columns are used at all. they also exist in the Services table
|
||||
cmd.Parameters["@prot"].Value = ci.Lock ? -1 : 0;
|
||||
cmd.Parameters["@sel"].Value = ci.Skip ? 0 : -1;
|
||||
cmd.Parameters["@vis"].Value = ci.Hidden ? 0 : -1;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.CommandText = $"update fav_{i + 1} set user_defined_ch_num=@chnr, user_defined_ch_name=@name where ui2_svc_id=@svcid and ui2_svc_rec_id=@recid";
|
||||
cmd.Parameters.Clear();
|
||||
cmd.Parameters.Add("@chnr", DbType.String); // for some reason this is a VARCHAR in the database
|
||||
cmd.Parameters.Add("@name", DbType.String);
|
||||
cmd.Parameters.Add("@svcid", DbType.Int32);
|
||||
cmd.Parameters.Add("@recid", DbType.Int32);
|
||||
cmd.Parameters["@chnr"].Value = ci.FavIndex[i].ToString();
|
||||
cmd.Parameters["@name"].Value = ci.Name;
|
||||
cmd.Parameters["@svcid"].Value = ci.RecordIndex >> 32;
|
||||
cmd.Parameters["@recid"].Value = ci.RecordIndex & 0xFFFF;
|
||||
if (cmd.ExecuteNonQuery() == 0)
|
||||
|
||||
// update the $all list with the same values
|
||||
if (pidAll != 0 && favId != pidAv)
|
||||
{
|
||||
cmd.CommandText = $"insert into fav_{i + 1} (ui2_svc_id, ui2_svc_rec_id, user_defined_ch_num, user_defined_ch_name) values (@svcid,@recid,@chnr,@name)";
|
||||
cmd.Parameters["@favId"].Value = pidAll;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region enums and bitmasks
|
||||
|
||||
internal enum BroadcastType
|
||||
#region UpdateUserFavoriteLists()
|
||||
private void UpdateUserFavoriteLists(SQLiteCommand cmd)
|
||||
{
|
||||
Analog = 1,
|
||||
Dvb = 2
|
||||
}
|
||||
// delete all FavoriteItem records that belong to the FAV1-4 lists
|
||||
cmd.Parameters.Clear();
|
||||
cmd.CommandText = "delete from FavoriteItem where FavoriteId in (select Pid from FavoriteList where name like 'FAV_')";
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
internal enum BroadcastMedium
|
||||
{
|
||||
DigTer = 1,
|
||||
DigCab = 2,
|
||||
DigSat = 3,
|
||||
AnaTer = 4,
|
||||
AnaCab = 5,
|
||||
AnaSat = 6
|
||||
}
|
||||
// (re-)insert the user's new favorites
|
||||
cmd.CommandText = "insert into FavoriteItem (FavoriteId, ServiceId, ChannelNum) values (@favId, @servId, @ch)";
|
||||
cmd.Parameters.Add("@favId", DbType.Int32);
|
||||
cmd.Parameters.Add("@servId", DbType.Int32);
|
||||
cmd.Parameters.Add("@ch", DbType.Int32);
|
||||
foreach (var entry in favListIdToFavIndex)
|
||||
{
|
||||
var favIndex = entry.Value;
|
||||
cmd.Parameters["@favId"].Value = entry.Key;
|
||||
foreach (var ci in userFavList.Channels)
|
||||
{
|
||||
if (ci.IsProxy) // ignore proxies for missing channels that might have been added by applying a reference list
|
||||
continue;
|
||||
|
||||
internal enum ServiceType
|
||||
{
|
||||
Tv = 1,
|
||||
Radio = 2,
|
||||
App = 3
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum NwMask
|
||||
{
|
||||
Active = 1 << 1,
|
||||
Visible = 1 << 3,
|
||||
Fav1 = 1 << 4,
|
||||
Fav2 = 1 << 5,
|
||||
Fav3 = 1 << 6,
|
||||
Fav4 = 1 << 7,
|
||||
Lock = 1 << 8
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum OptionMask
|
||||
{
|
||||
NameEdited = 1 << 3,
|
||||
ChNumEdited = 1 << 10,
|
||||
DeletedByUser = 1 << 13
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum HashCode
|
||||
{
|
||||
Name = 1 << 0,
|
||||
ChannelId = 1 << 1,
|
||||
BroadcastType = 1 << 2,
|
||||
TsRecId = 1 << 3,
|
||||
ProgNum = 1 << 4,
|
||||
DvbShortName = 1 << 5,
|
||||
Radio = 1 << 10,
|
||||
Encrypted = 1 << 11,
|
||||
Tv = 1 << 13
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum DvbLinkageMask
|
||||
{
|
||||
Ts = 1 << 2
|
||||
var num = ci.GetPosition(favIndex + 1);
|
||||
if (num > 0)
|
||||
{
|
||||
cmd.Parameters["@servId"].Value = ci.RecordIndex;
|
||||
cmd.Parameters["@ch"].Value = num;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
#define HISENSE_ENABLED
|
||||
using ChanSort.Api;
|
||||
|
||||
/*
|
||||
Support for the Hisense file format (Sep 2015) is currently disabled due to the risk of damaging the TV when
|
||||
users import files in an older/newer format than the currently installed firmware expects.
|
||||
*/
|
||||
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Hisense
|
||||
namespace ChanSort.Loader.Hisense2017
|
||||
{
|
||||
#if HISENSE_ENABLED
|
||||
public class HisDbSerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string PluginName => "Hisense servicelist.db";
|
||||
public string FileFilter => "servicelist*.db";
|
||||
public string FileFilter => "*.db";
|
||||
|
||||
#region CreateSerializer()
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
return new HisDbSerializer(inputFile);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ChanSort.Loader.Hisense {
|
||||
namespace ChanSort.Loader.Hisense2017 {
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace ChanSort.Loader.LG
|
||||
{
|
||||
public class TllFileSerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string PluginName { get { return "LG-Electronics xx*.tll"; } }
|
||||
public string PluginName { get { return "LG model specific (xx*.tll)"; } }
|
||||
public string FileFilter { get { return "xx*.TLL"; } }
|
||||
|
||||
#region CreateSerializer()
|
||||
|
||||
@@ -339,6 +339,11 @@ namespace ChanSort.Loader.Panasonic
|
||||
{
|
||||
RepairCorruptedDatabaseImage(cmd);
|
||||
InitCharacterEncoding(cmd);
|
||||
|
||||
cmd.CommandText = "SELECT count(1) FROM sqlite_master WHERE type = 'table' and name in ('svl', 'tsl')";
|
||||
if (Convert.ToInt32(cmd.ExecuteScalar()) != 2)
|
||||
throw new FileLoadException("File doesn't contain the expected TSL/SVL tables");
|
||||
|
||||
this.ReadChannels(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace ChanSort.Loader.Panasonic
|
||||
{
|
||||
public class SerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string PluginName { get { return "Panasonic *.db,*.bin"; } }
|
||||
public string PluginName { get { return "Panasonic"; } }
|
||||
public string FileFilter { get { return "*.db;*.bin"; } }
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
|
||||
@@ -144,6 +144,8 @@ namespace ChanSort.Loader.Samsung
|
||||
mapping.SetFlag(_Lock, this.Lock);
|
||||
mapping.SetFlag(_Deleted, this.NewProgramNr < 0);
|
||||
mapping.SetFlag(_IsActive, this.NewProgramNr >= 0);
|
||||
if (this.Encrypted != null)
|
||||
mapping.SetFlag(_Encrypted, this.Encrypted.Value);
|
||||
this.UpdateChecksum();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace ChanSort.Loader.Samsung
|
||||
this.ReadConfigurationFromIniFile();
|
||||
this.Features.ChannelNameEdit = ChannelNameEditMode.All;
|
||||
this.Features.CleanUpChannelData = true;
|
||||
this.Features.EncryptedFlagEdit = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace ChanSort.Loader.Samsung
|
||||
{
|
||||
public class ScmSerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string PluginName { get { return "Samsung *.scm"; } }
|
||||
public string PluginName { get { return "Samsung B-H series"; } }
|
||||
public string FileFilter { get { return "*.scm"; } }
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ChanSort.Loader.SamsungJ</RootNamespace>
|
||||
<AssemblyName>ChanSort.Loader.SamsungJ</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
||||
@@ -55,7 +55,11 @@ namespace ChanSort.Loader.SamsungJ
|
||||
catch { }
|
||||
}
|
||||
|
||||
foreach (var filePath in Directory.GetFiles(tempDir, "*."))
|
||||
var files = Directory.GetFiles(tempDir, "*.");
|
||||
if (files.Length == 0)
|
||||
throw new FileLoadException("The Samsung .zip channel list archive does not contain any supported files.");
|
||||
|
||||
foreach (var filePath in files)
|
||||
{
|
||||
var filename = Path.GetFileName(filePath) ?? "";
|
||||
if (filename.StartsWith("vconf_"))
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace ChanSort.Loader.SamsungJ
|
||||
{
|
||||
public class DbSerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string PluginName => "Samsung J-Series (*.zip)";
|
||||
public string PluginName => "Samsung J-K series";
|
||||
public string FileFilter => "*.zip"; // "channel_list_t*.zip";
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace ChanSort.Loader.Toshiba
|
||||
{
|
||||
public class DbSerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string PluginName => "Toshiba *.zip";
|
||||
public string FileFilter => "Hotel*.zip";
|
||||
public string PluginName => "Toshiba";
|
||||
public string FileFilter => "*.zip";
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace ChanSort.Loader.VDR
|
||||
{
|
||||
public class SerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string PluginName { get { return "VDR Channels *.conf"; } }
|
||||
public string PluginName { get { return "Linux VDR"; } }
|
||||
public string FileFilter { get { return "*.conf"; } }
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
|
||||
@@ -332,6 +332,42 @@
|
||||
<Project>{DCCFFA08-472B-4D17-BB90-8F513FC01392}</Project>
|
||||
<Name>ChanSort.Api</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.GlobalClone\ChanSort.Loader.GlobalClone.csproj">
|
||||
<Project>{5361c8cb-f737-4709-af8c-e1f0456f3c5b}</Project>
|
||||
<Name>ChanSort.Loader.GlobalClone</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.Hisense2017\ChanSort.Loader.Hisense2017.csproj">
|
||||
<Project>{9282e1db-cd1f-400a-aca1-17e0c4562acf}</Project>
|
||||
<Name>ChanSort.Loader.Hisense2017</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.Hisense\ChanSort.Loader.Hisense.csproj">
|
||||
<Project>{d093e7ee-d3ad-4e7b-af82-c6918ca017fb}</Project>
|
||||
<Name>ChanSort.Loader.Hisense</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.LG\ChanSort.Loader.LG.csproj">
|
||||
<Project>{e972d8a1-2f5f-421c-ac91-cff45e5191be}</Project>
|
||||
<Name>ChanSort.Loader.LG</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.Panasonic\ChanSort.Loader.Panasonic.csproj">
|
||||
<Project>{68da8072-3a29-4076-9f64-d66f38349585}</Project>
|
||||
<Name>ChanSort.Loader.Panasonic</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.SamsungJ\ChanSort.Loader.SamsungJ.csproj">
|
||||
<Project>{33897002-0537-49a4-b963-a18d17311b3d}</Project>
|
||||
<Name>ChanSort.Loader.SamsungJ</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.Samsung\ChanSort.Loader.Samsung.csproj">
|
||||
<Project>{a1c9a98d-368a-44e8-9b7f-7eaca46c9ec5}</Project>
|
||||
<Name>ChanSort.Loader.Samsung</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.Toshiba\ChanSort.Loader.Toshiba.csproj">
|
||||
<Project>{f6f02792-07f1-48d5-9af3-f945ca5e3931}</Project>
|
||||
<Name>ChanSort.Loader.Toshiba</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.VDR\ChanSort.Loader.VDR.csproj">
|
||||
<Project>{74a18c6f-09ff-413e-90d9-827066fa5b36}</Project>
|
||||
<Name>ChanSort.Loader.VDR</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="app.ico" />
|
||||
|
||||
2
source/ChanSort/MainForm.Designer.cs
generated
2
source/ChanSort/MainForm.Designer.cs
generated
@@ -614,6 +614,7 @@
|
||||
this.gviewRight.ShownEditor += new System.EventHandler(this.gview_ShownEditor);
|
||||
this.gviewRight.FocusedRowChanged += new DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventHandler(this.gviewRight_FocusedRowChanged);
|
||||
this.gviewRight.CellValueChanged += new DevExpress.XtraGrid.Views.Base.CellValueChangedEventHandler(this.gviewRight_CellValueChanged);
|
||||
this.gviewRight.CustomColumnSort += new DevExpress.XtraGrid.Views.Base.CustomColumnSortEventHandler(this.gviewRight_CustomColumnSort);
|
||||
this.gviewRight.CustomUnboundColumnData += new DevExpress.XtraGrid.Views.Base.CustomColumnDataEventHandler(this.gview_CustomUnboundColumnData);
|
||||
this.gviewRight.CustomColumnDisplayText += new DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventHandler(this.gviewRight_CustomColumnDisplayText);
|
||||
this.gviewRight.LayoutUpgrade += new DevExpress.Utils.LayoutUpgradeEventHandler(this.gviewRight_LayoutUpgrade);
|
||||
@@ -639,6 +640,7 @@
|
||||
this.colSlotOld.Name = "colSlotOld";
|
||||
this.colSlotOld.OptionsColumn.AllowEdit = false;
|
||||
this.colSlotOld.OptionsFilter.AllowAutoFilter = false;
|
||||
this.colSlotOld.SortMode = DevExpress.XtraGrid.ColumnSortMode.Custom;
|
||||
this.colSlotOld.UnboundType = DevExpress.Data.UnboundColumnType.Integer;
|
||||
//
|
||||
// colSlotNew
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace ChanSort.Ui
|
||||
{
|
||||
public partial class MainForm : XtraForm
|
||||
{
|
||||
public const string AppVersion = "v2017-03-29";
|
||||
public const string AppVersion = "v2017-06-08";
|
||||
|
||||
private const int MaxMruEntries = 10;
|
||||
private readonly List<string> isoEncodings = new List<string>();
|
||||
@@ -186,12 +186,17 @@ namespace ChanSort.Ui
|
||||
numberOfFilters = 0;
|
||||
var filter = new StringBuilder();
|
||||
var extension = new StringBuilder();
|
||||
foreach (var plugin in this.Plugins)
|
||||
var sortedPlugins = this.Plugins.ToList();
|
||||
sortedPlugins.Sort((a, b) => a.PluginName.CompareTo(b.PluginName));
|
||||
foreach (var plugin in sortedPlugins)
|
||||
{
|
||||
filter.Append(plugin.PluginName).Append("|").Append(plugin.FileFilter);
|
||||
extension.Append(plugin.FileFilter);
|
||||
filter.Append("|");
|
||||
extension.Append(";");
|
||||
if (!(";" + extension + ";").Contains(plugin.FileFilter))
|
||||
{
|
||||
extension.Append(plugin.FileFilter);
|
||||
extension.Append(";");
|
||||
}
|
||||
++numberOfFilters;
|
||||
}
|
||||
if (extension.Length > 0)
|
||||
@@ -252,7 +257,7 @@ namespace ChanSort.Ui
|
||||
this.Editor.ChannelList = null;
|
||||
this.gridRight.DataSource = null;
|
||||
this.gridLeft.DataSource = null;
|
||||
this.FillChannelListCombo();
|
||||
this.FillChannelListTabs();
|
||||
|
||||
//this.SetControlsEnabled(!this.dataRoot.IsEmpty);
|
||||
this.UpdateFavoritesEditor(this.DataRoot.SupportedFavorites);
|
||||
@@ -314,9 +319,9 @@ namespace ChanSort.Ui
|
||||
|
||||
#endregion
|
||||
|
||||
#region FillChannelListCombo()
|
||||
#region FillChannelListTabs()
|
||||
|
||||
private void FillChannelListCombo()
|
||||
private void FillChannelListTabs()
|
||||
{
|
||||
this.tabChannelList.TabPages.Clear();
|
||||
|
||||
@@ -408,23 +413,60 @@ namespace ChanSort.Ui
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetTvFileSerializer()
|
||||
#region GetSerializerForFile()
|
||||
|
||||
internal ISerializerPlugin GetPluginForFile(string inputFileName)
|
||||
internal SerializerBase GetSerializerForFile(string inputFileName, ref ISerializerPlugin hint)
|
||||
{
|
||||
if (!File.Exists(inputFileName))
|
||||
{
|
||||
XtraMessageBox.Show(this, string.Format(Resources.MainForm_LoadTll_SourceTllNotFound, inputFileName));
|
||||
return null;
|
||||
}
|
||||
var upperFileName = (Path.GetFileName(inputFileName) ?? "").ToUpper();
|
||||
foreach (var plugin in this.Plugins)
|
||||
|
||||
List<ISerializerPlugin> candidates = new List<ISerializerPlugin>();
|
||||
if (hint != null)
|
||||
candidates.Add(hint);
|
||||
else
|
||||
{
|
||||
foreach (var filter in plugin.FileFilter.ToUpper().Split(';'))
|
||||
var upperFileName = (Path.GetFileName(inputFileName) ?? "").ToUpper();
|
||||
foreach (var plugin in this.Plugins)
|
||||
{
|
||||
var regex = filter.Replace(".", "\\.").Replace("*", ".*").Replace("?", ".");
|
||||
if (Regex.IsMatch(upperFileName, regex))
|
||||
return plugin;
|
||||
foreach (var filter in plugin.FileFilter.ToUpper().Split(';'))
|
||||
{
|
||||
var regex = filter.Replace(".", "\\.").Replace("*", ".*").Replace("?", ".");
|
||||
if (Regex.IsMatch(upperFileName, regex))
|
||||
{
|
||||
candidates.Add(plugin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var plugin in candidates)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serializer = plugin.CreateSerializer(inputFileName);
|
||||
if (serializer != null)
|
||||
{
|
||||
serializer.DefaultEncoding = this.defaultEncoding;
|
||||
serializer.Load();
|
||||
hint = plugin;
|
||||
return serializer;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is ArgumentException)
|
||||
{
|
||||
var msg = ex.ToString();
|
||||
if (msg.Contains("ZipFile..ctor()"))
|
||||
{
|
||||
XtraMessageBox.Show(this, string.Format(Resources.MainForm_LoadTll_InvalidZip, inputFileName));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,18 +488,14 @@ namespace ChanSort.Ui
|
||||
return false;
|
||||
}
|
||||
|
||||
if (plugin == null)
|
||||
plugin = this.GetPluginForFile(tvDataFile);
|
||||
// abort action if there is no currentTvSerializer for the input file
|
||||
var serializer = plugin == null ? null : plugin.CreateSerializer(tvDataFile);
|
||||
SerializerBase serializer = this.GetSerializerForFile(tvDataFile, ref plugin);
|
||||
if (serializer == null)
|
||||
return false;
|
||||
|
||||
if (!this.PromptSaveAndContinue())
|
||||
return false;
|
||||
|
||||
serializer.DefaultEncoding = this.defaultEncoding;
|
||||
serializer.Load();
|
||||
this.SetFileName(tvDataFile);
|
||||
this.currentPlugin = plugin;
|
||||
this.currentTvSerializer = serializer;
|
||||
@@ -530,6 +568,7 @@ namespace ChanSort.Ui
|
||||
this.BeginInvoke((Action) (() => this.ShowOpenReferenceFileDialog(false)));
|
||||
else if (res == DialogResult.No)
|
||||
{
|
||||
//this.currentTvSerializer.ApplyCurrentProgramNumbers();
|
||||
this.DataRoot.ApplyCurrentProgramNumbers();
|
||||
this.RefreshGrid(this.gviewLeft, this.gviewRight);
|
||||
this.rbInsertSwap.Checked = true;
|
||||
@@ -590,9 +629,6 @@ namespace ChanSort.Ui
|
||||
this.pageProgNr.PageVisible = true;
|
||||
this.grpSubList.Visible = DataRoot.SortedFavorites;
|
||||
}
|
||||
|
||||
//this.tabSubList.TabPages[0].PageVisible = !channelList.IsMixedSourceFavoritesList;
|
||||
//this.pageProgNr.Enabled = this.pageProgNr.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -610,7 +646,7 @@ namespace ChanSort.Ui
|
||||
UpdateGridReadOnly();
|
||||
|
||||
|
||||
this.UpdateInsertSlotTextBox();
|
||||
this.UpdateInsertSlotNumber();
|
||||
this.UpdateMenu();
|
||||
|
||||
this.mnuFavList.Enabled = this.grpSubList.Visible;
|
||||
@@ -703,7 +739,7 @@ namespace ChanSort.Ui
|
||||
{
|
||||
foreach (var channel in list.Channels)
|
||||
{
|
||||
if (channel.NewProgramNr < 0)
|
||||
if (channel.NewProgramNr < 0 && channel.OldProgramNr >= 0)
|
||||
{
|
||||
hasUnsorted = true;
|
||||
break;
|
||||
@@ -871,6 +907,8 @@ namespace ChanSort.Ui
|
||||
// remove all the selected channels which are about to be added.
|
||||
// This may require an adjustment of the insert position when channels are removed in front of it and gaps are closed.
|
||||
var insertSlot = this.CurrentChannelList.InsertProgramNumber;
|
||||
if (insertSlot == 1 && this.rbInsertAfter.Checked && this.gviewLeft.RowCount == 0)
|
||||
insertSlot = 0;
|
||||
var contextRow = (ChannelInfo)this.gviewLeft.GetFocusedRow();
|
||||
if (contextRow != null)
|
||||
{
|
||||
@@ -1684,7 +1722,7 @@ namespace ChanSort.Ui
|
||||
if (this.currentTvSerializer != null && this.currentTvSerializer.Features.CleanUpChannelData)
|
||||
{
|
||||
var msg = this.currentTvSerializer.CleanUpChannelData();
|
||||
this.FillChannelListCombo();
|
||||
this.FillChannelListTabs();
|
||||
InfoBox.Show(this, msg, this.miCleanupChannels.Caption);
|
||||
this.RefreshGrid(gviewLeft, gviewRight);
|
||||
}
|
||||
@@ -1837,11 +1875,13 @@ namespace ChanSort.Ui
|
||||
this.gviewLeft.BeginSort();
|
||||
this.gviewLeft.EndSort();
|
||||
this.gviewRight.BeginSort();
|
||||
if (this.subListIndex > 0)
|
||||
if (this.subListIndex > 0 && !this.CurrentChannelList.IsMixedSourceFavoritesList)
|
||||
this.colPrNr.FilterInfo = new ColumnFilterInfo("[NewProgramNr]<>-1");
|
||||
else
|
||||
this.colPrNr.ClearFilter();
|
||||
this.gviewRight.EndSort();
|
||||
|
||||
this.UpdateInsertSlotNumber();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -2050,7 +2090,7 @@ namespace ChanSort.Ui
|
||||
{
|
||||
var channel = (ChannelInfo) this.gviewLeft.GetRow(e.RowHandle);
|
||||
if (channel == null) return;
|
||||
if (channel.OldProgramNr == -1)
|
||||
if (channel.IsProxy)
|
||||
{
|
||||
e.Appearance.ForeColor = Color.Red;
|
||||
e.Appearance.Options.UseForeColor = true;
|
||||
@@ -2190,7 +2230,7 @@ namespace ChanSort.Ui
|
||||
{
|
||||
var channel = (ChannelInfo) this.gviewRight.GetRow(e.RowHandle);
|
||||
if (channel == null) return;
|
||||
if (channel.OldProgramNr == -1)
|
||||
if (channel.IsProxy)
|
||||
{
|
||||
e.Appearance.ForeColor = Color.Red;
|
||||
e.Appearance.Options.UseForeColor = true;
|
||||
@@ -2261,6 +2301,22 @@ namespace ChanSort.Ui
|
||||
|
||||
#endregion
|
||||
|
||||
#region gviewRight_CustomColumnSort
|
||||
private void gviewRight_CustomColumnSort(object sender, CustomColumnSortEventArgs e)
|
||||
{
|
||||
if (e.Column == this.colSlotOld)
|
||||
{
|
||||
// sort unassigned channels (PrNr = -1) to the bottom of the list
|
||||
var ch1 = (int)this.gviewRight.GetListSourceRowCellValue(e.ListSourceRowIndex1, e.Column);
|
||||
var ch2 = (int)this.gviewRight.GetListSourceRowCellValue(e.ListSourceRowIndex2, e.Column);
|
||||
if (ch1 < 0) ch1 = int.MaxValue;
|
||||
if (ch2 < 0) ch2 = int.MaxValue;
|
||||
e.Result = System.Collections.Comparer.Default.Compare(ch1, ch2);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region gviewRight_PopupMenuShowing
|
||||
|
||||
private void gviewRight_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
|
||||
@@ -2286,10 +2342,16 @@ namespace ChanSort.Ui
|
||||
if (this.CurrentChannelList == null)
|
||||
return;
|
||||
|
||||
var delta = this.curEditMode == EditMode.InsertAfter
|
||||
? -1
|
||||
: this.rbInsertAfter.Checked ? +1 : 0;
|
||||
this.CurrentChannelList.InsertProgramNumber += delta;
|
||||
if (this.gviewLeft.RowCount == 0)
|
||||
this.CurrentChannelList.InsertProgramNumber = 1;
|
||||
else
|
||||
{
|
||||
var delta = this.curEditMode == EditMode.InsertAfter
|
||||
? -1
|
||||
: this.rbInsertAfter.Checked ? +1 : 0;
|
||||
this.CurrentChannelList.InsertProgramNumber += delta;
|
||||
}
|
||||
|
||||
this.UpdateInsertSlotTextBox();
|
||||
this.curEditMode = this.rbInsertBefore.Checked
|
||||
? EditMode.InsertBefore
|
||||
@@ -2458,8 +2520,9 @@ namespace ChanSort.Ui
|
||||
{
|
||||
this.gviewRight.BeginSort();
|
||||
this.gviewRight.ClearColumnsFilter();
|
||||
this.colSlotOld.FilterInfo = new ColumnFilterInfo("[OldProgramNr]<>-1");
|
||||
if (this.subListIndex > 0)
|
||||
if (this.DataRoot != null && !this.DataRoot.ShowDeletedChannels)
|
||||
this.colSlotOld.FilterInfo = new ColumnFilterInfo("[OldProgramNr]<>-1");
|
||||
if (this.subListIndex > 0 && !this.CurrentChannelList.IsMixedSourceFavoritesList)
|
||||
this.colPrNr.FilterInfo = new ColumnFilterInfo("[NewProgramNr]<>-1");
|
||||
this.gviewRight.EndSort();
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
</data>
|
||||
<data name="colUid1.Caption" xml:space="preserve">
|
||||
<value>UID</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="colOutLock.Caption" xml:space="preserve">
|
||||
<value>Lock</value>
|
||||
</data>
|
||||
@@ -373,7 +373,7 @@
|
||||
</data>
|
||||
<data name="grpSubList.Text" xml:space="preserve">
|
||||
<value>Sub List</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="grpSubList.Visible" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
@@ -466,37 +466,37 @@
|
||||
</data>
|
||||
<data name="miFavASet.Caption" xml:space="preserve">
|
||||
<value>&A</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miFavBSet.Caption" xml:space="preserve">
|
||||
<value>&B</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miFavCSet.Caption" xml:space="preserve">
|
||||
<value>&C</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miFavDSet.Caption" xml:space="preserve">
|
||||
<value>&D</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miFavESet.Caption" xml:space="preserve">
|
||||
<value>&E</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="mnuFavUnset.Caption" xml:space="preserve">
|
||||
<value>Remove from Favorites</value>
|
||||
</data>
|
||||
<data name="miFavAUnset.Caption" xml:space="preserve">
|
||||
<value>&A</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miFavBUnset.Caption" xml:space="preserve">
|
||||
<value>&B</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miFavCUnset.Caption" xml:space="preserve">
|
||||
<value>&C</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miFavDUnset.Caption" xml:space="preserve">
|
||||
<value>&D</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miFavEUnset.Caption" xml:space="preserve">
|
||||
<value>&E</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miLockOn.Caption" xml:space="preserve">
|
||||
<value>&Lock channel: on</value>
|
||||
</data>
|
||||
@@ -535,16 +535,16 @@
|
||||
</data>
|
||||
<data name="miEnglish.Caption" xml:space="preserve">
|
||||
<value>&English</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miGerman.Caption" xml:space="preserve">
|
||||
<value>&Deutsch</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miPortuguese.Caption" xml:space="preserve">
|
||||
<value>Português</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miRussian.Caption" xml:space="preserve">
|
||||
<value>ру́сский</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miCzech.Caption" xml:space="preserve">
|
||||
<value>Česky</value>
|
||||
</data>
|
||||
@@ -580,7 +580,7 @@
|
||||
</data>
|
||||
<data name="mnuInputSource.Caption" xml:space="preserve">
|
||||
<value>mnuInputSource</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="mnuGotoFavList.AccessibleDescription" xml:space="preserve">
|
||||
<value>Opens a submenu for the program of favorite list selection. This menu can be directly activated with the Shift+F1 key</value>
|
||||
</data>
|
||||
@@ -589,7 +589,7 @@
|
||||
</data>
|
||||
<data name="mnuFavList.Caption" xml:space="preserve">
|
||||
<value>mnuFavList</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="miSelectFavList0.Caption" xml:space="preserve">
|
||||
<value>Program list</value>
|
||||
</data>
|
||||
@@ -1013,7 +1013,7 @@
|
||||
</data>
|
||||
<data name="txtSetSlot.Properties.Mask.EditMask" xml:space="preserve">
|
||||
<value>\d{1,4}</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="txtSetSlot.Properties.Mask.MaskType" type="DevExpress.XtraEditors.Mask.MaskType, DevExpress.XtraEditors.v15.2">
|
||||
<value>RegEx</value>
|
||||
</data>
|
||||
@@ -1852,7 +1852,7 @@
|
||||
<value>DevExpress.XtraEditors.XtraForm, DevExpress.Utils.v15.2, Version=15.2.10.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a</value>
|
||||
</data>
|
||||
<data name="SharedImageCollection.Timestamp" type="System.DateTime, mscorlib">
|
||||
<value>01/26/2017 12:52:08</value>
|
||||
<value>06/08/2017 17:07:00</value>
|
||||
</data>
|
||||
<data name="SharedImageCollection.ImageSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>16, 16</value>
|
||||
@@ -1898,7 +1898,7 @@
|
||||
</data>
|
||||
<data name="btnToggleFavE.Text" xml:space="preserve">
|
||||
<value>±E</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name=">>btnToggleFavE.Name" xml:space="preserve">
|
||||
<value>btnToggleFavE</value>
|
||||
</data>
|
||||
@@ -1925,7 +1925,7 @@
|
||||
</data>
|
||||
<data name="btnToggleFavD.Text" xml:space="preserve">
|
||||
<value>±D</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name=">>btnToggleFavD.Name" xml:space="preserve">
|
||||
<value>btnToggleFavD</value>
|
||||
</data>
|
||||
@@ -1952,7 +1952,7 @@
|
||||
</data>
|
||||
<data name="btnToggleFavC.Text" xml:space="preserve">
|
||||
<value>±C</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name=">>btnToggleFavC.Name" xml:space="preserve">
|
||||
<value>btnToggleFavC</value>
|
||||
</data>
|
||||
@@ -1979,7 +1979,7 @@
|
||||
</data>
|
||||
<data name="btnToggleFavB.Text" xml:space="preserve">
|
||||
<value>±B</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name=">>btnToggleFavB.Name" xml:space="preserve">
|
||||
<value>btnToggleFavB</value>
|
||||
</data>
|
||||
@@ -2006,7 +2006,7 @@
|
||||
</data>
|
||||
<data name="btnToggleFavA.Text" xml:space="preserve">
|
||||
<value>±A</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name=">>btnToggleFavA.Name" xml:space="preserve">
|
||||
<value>btnToggleFavA</value>
|
||||
</data>
|
||||
@@ -2213,7 +2213,7 @@
|
||||
</data>
|
||||
<data name="splitContainerControl1.Panel1.Text" xml:space="preserve">
|
||||
<value>Panel1</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="gridRight.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
@@ -2438,7 +2438,7 @@
|
||||
</data>
|
||||
<data name="colTransportStreamId.Caption" xml:space="preserve">
|
||||
<value>TS ID</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="colTransportStreamId.ToolTip" xml:space="preserve">
|
||||
<value>Transport Stream ID</value>
|
||||
</data>
|
||||
@@ -2534,7 +2534,7 @@
|
||||
</data>
|
||||
<data name="colUid.Caption" xml:space="preserve">
|
||||
<value>Uid</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="colUid.Width" type="System.Int32, mscorlib">
|
||||
<value>120</value>
|
||||
</data>
|
||||
@@ -2801,7 +2801,7 @@ specific provider, satellite or country lists.</value>
|
||||
</data>
|
||||
<data name="splitContainerControl1.Panel2.Text" xml:space="preserve">
|
||||
<value>Panel2</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name="splitContainerControl1.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>1444, 459</value>
|
||||
</data>
|
||||
@@ -2810,7 +2810,7 @@ specific provider, satellite or country lists.</value>
|
||||
</data>
|
||||
<data name="splitContainerControl1.Text" xml:space="preserve">
|
||||
<value>splitContainerControl1</value>
|
||||
<comment>@Invariant</comment></data>
|
||||
</data>
|
||||
<data name=">>splitContainerControl1.Name" xml:space="preserve">
|
||||
<value>splitContainerControl1</value>
|
||||
</data>
|
||||
|
||||
11
source/ChanSort/Properties/Resources.Designer.cs
generated
11
source/ChanSort/Properties/Resources.Designer.cs
generated
@@ -238,6 +238,17 @@ namespace ChanSort.Ui.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The file is not a valid .zip archive.
|
||||
///TVs often export corrupted files to USB sticks formatted with the NTFS file system.
|
||||
///Please try exporting to a stick formatted with FAT32.
|
||||
/// </summary>
|
||||
internal static string MainForm_LoadTll_InvalidZip {
|
||||
get {
|
||||
return ResourceManager.GetString("MainForm_LoadTll_InvalidZip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to No plugin found to read/write {0} files..
|
||||
/// </summary>
|
||||
|
||||
@@ -292,4 +292,9 @@ Mögliche Ursachen sind USB-Sticks, die mit NTFS formatiert sind (FAT32 sollte i
|
||||
<data name="ReferenceListForm_ShowOpenFileDialog_Title" xml:space="preserve">
|
||||
<value>Wählen Sie eine Vorlagedatei für die Senderreihenfolge</value>
|
||||
</data>
|
||||
<data name="MainForm_LoadTll_InvalidZip" xml:space="preserve">
|
||||
<value>Diese Datei ist kein gültiges .zip Archiv.
|
||||
TVs exportieren oft defekte Dateien auf USB Sticks, die mit NTFS formatiert sind.
|
||||
Bitte versuchen Sie, die Senderliste auf einen Stick mit FAT32 Formatierung zu exportieren.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -296,4 +296,9 @@ or firmware upgrades without running a new channel scan.
|
||||
<data name="MainForm_ShowOpenReferenceFileDialog_Title" xml:space="preserve">
|
||||
<value>Open Reference List</value>
|
||||
</data>
|
||||
<data name="MainForm_LoadTll_InvalidZip" xml:space="preserve">
|
||||
<value>The file is not a valid .zip archive.
|
||||
TVs often export corrupted files to USB sticks formatted with the NTFS file system.
|
||||
Please try exporting to a stick formatted with FAT32</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -76,10 +76,8 @@ namespace ChanSort.Ui
|
||||
if (main.DetectCommonFileCorruptions(dlg.FileName))
|
||||
return null;
|
||||
|
||||
var plugin = dlg.FilterIndex <= main.Plugins.Count ? main.Plugins[dlg.FilterIndex - 1] : main.GetPluginForFile(dlg.FileName);
|
||||
var ser = plugin.CreateSerializer(dlg.FileName);
|
||||
ser.Load();
|
||||
return ser;
|
||||
ISerializerPlugin hint = dlg.FilterIndex <= main.Plugins.Count ? main.Plugins[dlg.FilterIndex - 1] : null;
|
||||
return main.GetSerializerForFile(dlg.FileName, ref hint);
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.IO;
|
||||
using ChanSort.Loader.Samsung;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
@@ -7,14 +8,41 @@ namespace Test.Loader.Samsung
|
||||
[TestClass]
|
||||
public class FileFormatDetectionTest
|
||||
{
|
||||
private readonly StringBuilder errors = new StringBuilder();
|
||||
private const string RootPath = @"d:\sources\ChanSort\TestFiles_Samsung\";
|
||||
private static readonly string RootPath;
|
||||
|
||||
static FileFormatDetectionTest()
|
||||
{
|
||||
RootPath = GetSolutionBaseDir() + @"\Test.Loader.Samsung\TestFiles\";
|
||||
}
|
||||
|
||||
#region GetSolutionBaseDir()
|
||||
protected static string GetSolutionBaseDir()
|
||||
{
|
||||
var dir = Path.GetDirectoryName(typeof(FileFormatDetectionTest).Assembly.Location);
|
||||
do
|
||||
{
|
||||
if (File.Exists(dir + "\\ChanSort.sln"))
|
||||
return dir;
|
||||
dir = Path.GetDirectoryName(dir);
|
||||
} while (!string.IsNullOrEmpty(dir));
|
||||
|
||||
dir = Environment.CurrentDirectory;
|
||||
do
|
||||
{
|
||||
if (File.Exists(dir + "\\ChanSort.sln"))
|
||||
return dir;
|
||||
dir = Path.GetDirectoryName(dir);
|
||||
} while (!string.IsNullOrEmpty(dir));
|
||||
|
||||
throw new InvalidOperationException("Cannot determine base directory of ChanSort solution");
|
||||
}
|
||||
#endregion
|
||||
|
||||
[TestMethod]
|
||||
public void LoadFileWithExcessiveHighFrequency_1()
|
||||
{
|
||||
// this seems to be a corrupt file caused by a buffer-overflow from analog channel names into the frequency data bytes
|
||||
var s = new ScmSerializer(RootPath + @"ThomasSaur_DH\channel_list_UE55H6470_1201-Suchlauf-2015-04-26.scm");
|
||||
var s = new ScmSerializer(RootPath + @"channel_list_UE55H6470_1201-Suchlauf-2015-04-26.scm");
|
||||
s.Load();
|
||||
}
|
||||
|
||||
@@ -22,7 +50,7 @@ namespace Test.Loader.Samsung
|
||||
public void LoadFileWithExcessiveHighFrequency_2()
|
||||
{
|
||||
// this seems to be a corrupt file caused by a buffer-overflow from analog channel names into the frequency data bytes
|
||||
var s = new ScmSerializer(RootPath + @"ThomasSaur_DH\channel_list_UE55H6470_1201.scm");
|
||||
var s = new ScmSerializer(RootPath + @"channel_list_UE55H6470_1201.scm");
|
||||
s.Load();
|
||||
}
|
||||
|
||||
@@ -30,7 +58,7 @@ namespace Test.Loader.Samsung
|
||||
public void LoadRenamedFile_HE40Cxxx_1201()
|
||||
{
|
||||
// This file uses the 1201 format (E,F,H,J), but has a "C" in its model name
|
||||
var s = new ScmSerializer(RootPath + @"__C=F\Kinig\Reier Monika.scm");
|
||||
var s = new ScmSerializer(RootPath + @"E_format_with_C_model_name.scm");
|
||||
s.Load();
|
||||
Assert.AreEqual("E", s.Series);
|
||||
}
|
||||
@@ -39,7 +67,7 @@ namespace Test.Loader.Samsung
|
||||
public void LoadRenamedFile_LT24B_1201()
|
||||
{
|
||||
// This file uses the 1201 format (E,F,H,J), but has a "B" in its model name
|
||||
var s = new ScmSerializer(RootPath + @"__B=F\DieterHerzberg_B\renamed.scm");
|
||||
var s = new ScmSerializer(RootPath + @"E_format_with_C_model_name.scm");
|
||||
s.Load();
|
||||
Assert.AreEqual("E", s.Series);
|
||||
}
|
||||
@@ -47,8 +75,8 @@ namespace Test.Loader.Samsung
|
||||
[TestMethod]
|
||||
public void LoadJSeriesWithScm1201Format()
|
||||
{
|
||||
// J-series model with SCM format
|
||||
var s = new ScmSerializer(RootPath + @"__J\HenryLoenwind_SCM\channel_list_UE32J5170_1201_orig.scm");
|
||||
// J-series model with E-J series SCM format
|
||||
var s = new ScmSerializer(RootPath + @"channel_list_UE32J5170_1201_orig.scm");
|
||||
s.Load();
|
||||
Assert.AreEqual("E", s.Series);
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,18 @@
|
||||
ChanSort Change Log
|
||||
===================
|
||||
|
||||
2017-06-08
|
||||
- added experimental support for Loewe / Hisense 2017 servicelist.db
|
||||
file format
|
||||
- show error message when trying to open a .zip file that doen't contain
|
||||
the expected files of a Samsung J series or Toshiba .zip channel list
|
||||
- show error message when trying to open a broken .zip file, which is
|
||||
most likely caused by exporting to a USB stick formatted with NTFS
|
||||
- allow changing the "crypt" flag for Samsung .scm lists
|
||||
- less reliable on file name / extension to detect file format
|
||||
(trying all loaders which support the file extension until one can
|
||||
successfully read the file)
|
||||
|
||||
2017-01-26
|
||||
- added Czech translation (thanks to Pavel Mizera)
|
||||
- fixed error when opening latest Hisense channel.db file format
|
||||
|
||||
Reference in New Issue
Block a user