Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Group specific channel numbering to matching backend bouquets #251

Merged
merged 5 commits into from Oct 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -64,6 +64,7 @@ set(VUPLUS_HEADERS src/client.h
src/enigma2/data/BaseEntry.h
src/enigma2/data/Channel.h
src/enigma2/data/ChannelGroup.h
src/enigma2/data/ChannelGroupMember.h
src/enigma2/data/EpgEntry.h
src/enigma2/data/EpgPartialEntry.h
src/enigma2/data/EpgChannel.h
Expand Down
19 changes: 10 additions & 9 deletions README.md
Expand Up @@ -19,7 +19,7 @@ This addon leverages the OpenWebIf project to interact with the Enigma2 device v
* Full Tuner Signal Support (Including Service Providers)
* Timer and Recording descriptions: If your provider only uses short description (plot outline) instead of long descrption (plot) then info will not be displayed pertaining to the shows in question. For OpenWebIf clients a JSON API is available to populate the missing data.
* Edit recording name, last played position and play count for recordings
* Bouquet Backend Channel Numbers
* Bouquet (and group specific) Backend Channel Numbers

Some features are only available with at least certain OpenWebIf versions:
* 1.3.0
Expand Down Expand Up @@ -135,13 +135,14 @@ Within this tab general options are configured.
### Channels
Within this tab options that refer to channel data can be set. When changing bouquets you may need to clear the channel cache to the settings to take effect. You can do this by going to the following in Kodi settings: `Settings->PVR & Live TV->General->Clear cache`.

Note that channel numbers are set in the addon based on their first occurence when loaded, i.e. if a channel appears in multiple bouqets the channel number will be taken from the first bouquet in which it is loaded, any subsequent channel numbers will be ignored. Therefore if it's desired to keep the same channel numbers across the Enigma2 device and the addon the following guidelines should be adhered to:
* If a master bouquet is used it should be the first bouquet loaded assuming it has the channel numbering/order you require.
* If not using a master bouquet each channel should only appear in a single bouquet (i.e. do not use channels in multiple bouquets unless they have different service references).
Note that channel numbers can be set in the addon based on either:
1. Their first occurence when loaded, i.e. if a channel appears in multiple bouqets the channel number will be taken from the first bouquet in which it is loaded, any subsequent channel numbers will be ignored. This is useful as regardless of what group you are using in Kodi-PVR you can jump to a channel easily as it will always have the same number.
2. Bouquet specific channel numbering, i.e. exactly as they appear in the backend. This can be useful when bouquet are used as differnt users (profile-like) lists of channels.

If Kodi PVR is set to use the channel numbers from the backend the numbers will match those on your STB. If this is not enabled each unique instance of a channel will be given the next free number starting from 1 (i.e. the 17th unique channel will be channel 17). Backend channel numbers will only work for OpenWebIf 1.3.5 and later and they have been tested using ABM (AutoBouquetsMaker).

* **Zap before channelswitch (i.e. for Single Tuner boxes)**: When using the addon with a single tuner box it may be necessary that the addon needs to be able to zap to another channel on the set-top box. If this option is enabled each channel switch in Kodi will also result in a channel switch on the set-top box. Please note that "allow channel switching" needs to be enabled in the webinterface on the set-top box.
* **Use group specific channel numbers from backend**: If this option is enabled then each group in kodi will match the exact channel numbers used on the backend bouquets. If disabled (default) each channel will only have a single backend channel number (first occurence when loaded).
* **Use standard channel service reference**: Usually service reference's for the channels are in a standard format like `1:0:1:27F6:806:2:11A0000:0:0:0:`. On occasion depending on provider they can be extended with some text e.g. `1:0:1:27F6:806:2:11A0000:0:0:0::UTV` or `1:0:1:27F6:806:2:11A0000:0:0:0::UTV + 1`. If this option is enabled then all read service reference's will be read as standard. This is default behaviour. Functionality like autotimers will always convert to a standard reference.
* **TV bouquet fetch mode**: Choose from one of the following three modes:
- `All bouquets` - Fetch all TV bouquets from the set-top box.
Expand Down Expand Up @@ -215,15 +216,15 @@ If setting padding in Kodi PVR it's only supported on certain timer types, i.e.

The addon provides the following types of timers and timer rules that the user can create:

* **Once off time/channel based**: This timer can be created from the add timer UI on the main PVR screen (It cannot be selected from the EPG UI). If running OpenWebIf the timer will be populated with the EPG Entry (if available) at the start time for that channel.
* **Repeating time/channel based**: This timer can be created from the add timer UI on the main PVR screen (It cannot be selected from the EPG UI). This type is a timer rule and generates timers. The timers that are generated cannot be edited and will be of the type `Once off timer (set by repeating time/channel based rule)`.
* **Once off timer (channel)**: This timer can be created from the add timer UI on the main PVR screen (It cannot be selected from the EPG UI). If running OpenWebIf the timer will be populated with the EPG Entry (if available) at the start time for that channel.
* **Repeating time/channel based**: This timer can be created from the add timer UI on the main PVR screen (It cannot be selected from the EPG UI). This type is a timer rule and generates timers. The timers that are generated cannot be edited and will be of the type `Once off timer (repeating)`.
* **One time guide-based**: This timer can be created from the EPG UI as well as when playing a channel. It is the timer used when the user selects `Record` when accessing an EPG entry. It will create a timer that starts and ends as per the EPG entry. If playing back a channel it will start from now until the end of the current show. If using OpenWebIf, for providers that only use short description (plot outline) the addon will retrieve the correct description if available and use it in both the timer and resulting recording.
* **Auto guide-based**: This is a search based timer rule, using the show name and other factors the Enigma2 device will create timers for EPG entries that satisfy the search. The timers it creates are not editable and will be of the type `Once off timer (set by auto guide-based rule)`.
* **Auto guide-based**: This is a search based timer rule, using the show name and other factors the Enigma2 device will create timers for EPG entries that satisfy the search. The timers it creates are not editable and will be of the type `Once off timer (auto)`.

In addition there are some timers that can only be created by the addon and are read only:

* **Once off timer (set by repeating time/channel based rule)**: Timer generated by a `Repeating time/channel based` timer rule. Will contain padding that can't be modified the same as the parent timer rule.
* **Once off timer (set by auto guide-based rule)**: Timer created by an `Auto guide-based` timer rule.
* **Once off timer (repeating)**: Timer generated by a `Repeating time/channel based` timer rule. Will contain padding that can't be modified the same as the parent timer rule.
* **Once off timer (auto)**: Timer created by an `Auto guide-based` timer rule.
* **Repeating guide-based**: This type can only be created directly on the Enigma2 device. The type exists to allow users to view the timers in the PVR UI.

**Timer settings**
Expand Down
8 changes: 7 additions & 1 deletion pvr.vuplus/addon.xml.in
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon
id="pvr.vuplus"
version="4.8.0"
version="4.9.0"
name="Enigma2 Client"
provider-name="Joerg Dembski and Ross Nicholson">
<requires>@ADDON_DEPENDS@</requires>
Expand Down Expand Up @@ -175,6 +175,12 @@
<disclaimer lang="zh_TW">這是測試版軟體!其原創作者並無法對於以下情況負責,包含:錄影失敗,不正確的定時設定,多餘時數,或任何產生的其它不良影響...</disclaimer>
<platform>@PLATFORM@</platform>
<news>
v4.9.0
- Added: Group specific channel numbering to matching backend bouquets
- Fixed: Fix recordings last played, playcount etc. broken since prior last PR: 248
- Added: Shorten timer type descriptions to suit UI better
- Fixed: Fixed broken playback for deleted recordings

v4.8.0
- Added: Support group (bouquet) channel order from the backend
- Added: Extract new/live/premiere as part of show info from EPG
Expand Down
6 changes: 6 additions & 0 deletions pvr.vuplus/changelog.txt
@@ -1,3 +1,9 @@
v4.9.0
- Added: Group specific channel numbering to matching backend bouquets
- Fixed: Fix recordings last played, playcount etc. broken since prior last PR: 248
- Added: Shorten timer type descriptions to suit UI better
- Fixed: Fixed broken playback for deleted recordings

v4.8.0
- Added: Support group (bouquet) channel order from the backend
- Added: Extract new/live/premiere as part of show info from EPG
Expand Down
18 changes: 13 additions & 5 deletions pvr.vuplus/resources/language/resource.language.en_gb/strings.po
Expand Up @@ -94,7 +94,10 @@ msgctxt "#30015"
msgid "Update interval"
msgstr ""

#empty string with id 30016
#label: Channels - usegroupspecificnumbers
msgctxt "#30016"
msgid "Use bouquet specific channel numbers from backend"
msgstr ""

#label: Recordings - onlycurrent
msgctxt "#30017"
Expand Down Expand Up @@ -747,17 +750,17 @@ msgstr ""

#application: Timers
msgctxt "#30420"
msgid "Once off timer (set by auto guide-based rule)"
msgid "Once off timer (auto)"
msgstr ""

#application: Timers
msgctxt "#30421"
msgid "Once off timer (set by repeating time/channel based rule)"
msgid "Once off timer (repeating)"
msgstr ""

#application: Timers
msgctxt "#30422"
msgid "Once off time/channel based"
msgid "Once off timer (channel)"
msgstr ""

#application: Timers
Expand Down Expand Up @@ -1068,7 +1071,12 @@ msgctxt "#30654"
msgid "The number of Radio bouquets to load when `Some bouquets` is the selected fetch mode. Up to 5 can be chosen. If more than 5 are required the 'Custom bouquets' fetch mode should be used instead."
msgstr ""

#empty strings from id 30655 to 30659
#help: Channels - usegroupspecificnumbers
msgctxt "#30655"
msgid "If this option is enabled then each group in kodi will match the exact channel numbers used on the backend bouquets. If disabled (default) each channel will only have a single backend channel number (first occurence when loaded)."
msgstr ""

#empty strings from id 30656 to 30659

#help info - EPG

Expand Down
6 changes: 5 additions & 1 deletion pvr.vuplus/resources/settings.xml
Expand Up @@ -226,6 +226,11 @@
<default>false</default>
<control type="toggle" />
</setting>
<setting id="usegroupspecificnumbers" type="boolean" label="30016" help="30655">
<level>0</level>
<default>false</default>
<control type="toggle" />
</setting>
<setting id="usestandardserviceref" type="boolean" label="30126" help="30641">
<level>3</level>
<default>true</default>
Expand All @@ -246,7 +251,6 @@
</constraints>
<control type="spinner" format="integer" />
</setting>

<setting id="numtvgroups" type="integer" parent="tvgroupmode" label="30134" help="30653">
<level>0</level>
<default>1</default>
Expand Down
8 changes: 4 additions & 4 deletions src/enigma2/ChannelGroups.cpp
Expand Up @@ -78,16 +78,16 @@ PVR_ERROR ChannelGroups::GetChannelGroupMembers(std::vector<PVR_CHANNEL_GROUP_ME

int channelOrder = 1;

for (const auto& channel : channelGroup->GetChannelList())
for (const auto& channelMember : channelGroup->GetChannelGroupMembers())
{
PVR_CHANNEL_GROUP_MEMBER tag = {0};

strncpy(tag.strGroupName, groupName.c_str(), sizeof(tag.strGroupName));
tag.iChannelUniqueId = channel->GetUniqueId();
tag.iChannelNumber = 0; // The addon or kodi-pvr do not currently support group specific channel numbers
tag.iChannelUniqueId = channelMember.GetChannel()->GetUniqueId();
tag.iChannelNumber = Settings::GetInstance().UseGroupSpecificChannelNumbers() ? channelMember.GetChannelNumber() : 0;
tag.iOrder = channelOrder; //Keep the channels in list order as per the groups on the STB

Logger::Log(LEVEL_DEBUG, "%s - add channel %s (%d) to group '%s' with channel order %d", __FUNCTION__, channel->GetChannelName().c_str(), tag.iChannelUniqueId, groupName.c_str(), channelOrder);
Logger::Log(LEVEL_DEBUG, "%s - add channel %s (%d) to group '%s' with channel order %d", __FUNCTION__, channelMember.GetChannel()->GetChannelName().c_str(), tag.iChannelUniqueId, groupName.c_str(), channelOrder);

channelGroupMembers.emplace_back(tag);

Expand Down
18 changes: 12 additions & 6 deletions src/enigma2/Channels.cpp
Expand Up @@ -157,15 +157,15 @@ void Channels::AddChannel(Channel& newChannel, std::shared_ptr<ChannelGroup>& ch

std::shared_ptr<Channel> channel = m_channels.back();
channel->AddChannelGroup(channelGroup);
channelGroup->AddChannel(channel);
channelGroup->AddChannelGroupMember(channel);

m_channelsUniqueIdMap.insert({channel->GetUniqueId(), channel});
m_channelsServiceReferenceMap.insert({channel->GetServiceReference(), channel});
}
else
{
foundChannel->AddChannelGroup(channelGroup);
channelGroup->AddChannel(foundChannel);
channelGroup->AddChannelGroupMember(foundChannel);
}
}

Expand Down Expand Up @@ -318,11 +318,17 @@ int Channels::LoadChannelsExtraData(const std::shared_ptr<enigma2::data::Channel
channel->SetProviderlName(jsonChannel["provider"].get<std::string>());
}

if (!jsonChannel["pos"].empty() && channel->UsingDefaultChannelNumber() && Settings::GetInstance().SupportsChannelNumberGroupStartPos())
if (!jsonChannel["pos"].empty() && Settings::GetInstance().SupportsChannelNumberGroupStartPos())
{
Logger::Log(LEVEL_DEBUG, "%s For Channel %s, set backend channel number to %d", __FUNCTION__, jsonChannel["servicename"].get<std::string>().c_str(), jsonChannel["pos"].get<int>());
channel->SetChannelNumber(jsonChannel["pos"].get<int>() + lastGroupLatestChannelPosition);
channel->SetUsingDefaultChannelNumber(false);
int channelNumber = jsonChannel["pos"].get<int>() + newChannelPositionOffset;
channelGroup->SetMemberChannelNumber(channel, channelNumber);

if (channel->UsingDefaultChannelNumber())
{
Logger::Log(LEVEL_DEBUG, "%s For Channel %s, set backend channel number to %d", __FUNCTION__, jsonChannel["servicename"].get<std::string>().c_str(), channelNumber);
channel->SetChannelNumber(channelNumber);
channel->SetUsingDefaultChannelNumber(false);
}
}

if (Settings::GetInstance().UseOpenWebIfPiconPath())
Expand Down
19 changes: 11 additions & 8 deletions src/enigma2/Recordings.cpp
Expand Up @@ -508,11 +508,11 @@ int Recordings::GetRecordingStreamProgramNumber(const PVR_RECORDING& recording)

const std::string Recordings::GetRecordingURL(const PVR_RECORDING& recinfo)
{
for (const auto& recording : m_recordings)
{
if (recinfo.strRecordingId == recording.GetRecordingId())
return recording.GetStreamURL();
}
auto recordingEntry = GetRecording(recinfo.strRecordingId);

if (!recordingEntry.GetRecordingId().empty())
return recordingEntry.GetStreamURL();

return "";
}

Expand Down Expand Up @@ -677,13 +677,14 @@ bool Recordings::LoadLocations()
void Recordings::LoadRecordings(bool deleted)
{
std::vector<RecordingEntry> newRecordingsList;
std::unordered_map<std::string, enigma2::data::RecordingEntry> newRecordingsIdMap;
bool loadError = false;
for (std::string location : m_locations)
{
if (deleted)
location += TRASH_FOLDER;

if (!GetRecordingsFromLocation(location, deleted, newRecordingsList))
if (!GetRecordingsFromLocation(location, deleted, newRecordingsList, newRecordingsIdMap))
{
loadError = true;
Logger::Log(LEVEL_ERROR, "%s Error fetching lists for folder: '%s'", __FUNCTION__, location.c_str());
Expand All @@ -696,10 +697,12 @@ void Recordings::LoadRecordings(bool deleted)
auto& recordings = (!deleted) ? m_recordings : m_deletedRecordings;

std::move(newRecordingsList.begin(), newRecordingsList.end(), std::back_inserter(recordings));
for (auto& pair : newRecordingsIdMap)
m_recordingsIdMap.insert(pair);
}
}

bool Recordings::GetRecordingsFromLocation(const std::string recordingLocation, bool deleted, std::vector<RecordingEntry>& recordings)
bool Recordings::GetRecordingsFromLocation(const std::string recordingLocation, bool deleted, std::vector<RecordingEntry>& recordings, std::unordered_map<std::string, enigma2::data::RecordingEntry>& recordingsIdMap)
{
std::string url;
std::string directory;
Expand Down Expand Up @@ -761,7 +764,7 @@ bool Recordings::GetRecordingsFromLocation(const std::string recordingLocation,
iNumRecordings++;

recordings.emplace_back(recordingEntry);
m_recordingsIdMap.insert({recordingEntry.GetRecordingId(), recordingEntry});
recordingsIdMap.insert({recordingEntry.GetRecordingId(), recordingEntry});

Logger::Log(LEVEL_DEBUG, "%s loaded Recording entry '%s', start '%d', length '%d'", __FUNCTION__, recordingEntry.GetTitle().c_str(), recordingEntry.GetStartTime(), recordingEntry.GetDuration());
}
Expand Down
2 changes: 1 addition & 1 deletion src/enigma2/Recordings.h
Expand Up @@ -68,7 +68,7 @@ namespace enigma2
private:
static const std::string FILE_NOT_FOUND_RESPONSE_SUFFIX;

bool GetRecordingsFromLocation(const std::string recordingFolder, bool deleted, std::vector<data::RecordingEntry>& recordings);
bool GetRecordingsFromLocation(const std::string recordingFolder, bool deleted, std::vector<data::RecordingEntry>& recordings, std::unordered_map<std::string, enigma2::data::RecordingEntry>& recordingsIdMap);
data::RecordingEntry GetRecording(const std::string& recordingId) const;
bool ReadExtaRecordingCutsInfo(const data::RecordingEntry& recordingEntry, std::vector<std::pair<int, int64_t>>& cuts, std::vector<std::string>& tags);
bool ReadExtraRecordingPlayCountInfo(const data::RecordingEntry& recordingEntry, std::vector<std::string>& tags);
Expand Down
5 changes: 5 additions & 0 deletions src/enigma2/Settings.cpp
Expand Up @@ -122,6 +122,9 @@ void Settings::ReadFromAddon()
if (!XBMC->GetSetting("zap", &m_zap))
m_zap = false;

if (!XBMC->GetSetting("usegroupspecificnumbers", &m_useGroupSpecificChannelNumbers))
m_useGroupSpecificChannelNumbers = false;

if (!XBMC->GetSetting("usestandardserviceref", &m_useStandardServiceReference))
m_useStandardServiceReference = true;

Expand Down Expand Up @@ -432,6 +435,8 @@ ADDON_STATUS Settings::SetValue(const std::string& settingName, const void* sett
//Channels
else if (settingName == "zap")
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_zap, ADDON_STATUS_OK, ADDON_STATUS_OK);
else if (settingName == "usegroupspecificnumbers")
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_useGroupSpecificChannelNumbers, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
else if (settingName == "usestandardserviceref")
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_useStandardServiceReference, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
else if (settingName == "tvgroupmode")
Expand Down
2 changes: 2 additions & 0 deletions src/enigma2/Settings.h
Expand Up @@ -161,6 +161,7 @@ namespace enigma2

//Channel
bool GetZapBeforeChannelSwitch() const { return m_zap; }
bool UseGroupSpecificChannelNumbers() const { return m_useGroupSpecificChannelNumbers; }
bool UseStandardServiceReference() const { return m_useStandardServiceReference; }
const ChannelGroupMode& GetTVChannelGroupMode() const { return m_tvChannelGroupMode; }
const std::string& GetCustomTVGroupsFile() const { return m_customTVGroupsFile; }
Expand Down Expand Up @@ -322,6 +323,7 @@ namespace enigma2

//Channel
bool m_zap = false;
bool m_useGroupSpecificChannelNumbers = false;
bool m_useStandardServiceReference = true;
ChannelGroupMode m_tvChannelGroupMode = ChannelGroupMode::ALL_GROUPS;
unsigned int m_numTVGroups = DEFAULT_NUM_GROUPS;
Expand Down