Skip to content

Commit

Permalink
Merge pull request #739 from phunkyfish/media-group-omega
Browse files Browse the repository at this point in the history
Media group omega
  • Loading branch information
phunkyfish authored Apr 26, 2023
2 parents 2143e85 + 59110d2 commit ab8002b
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 9 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ More detail on these can be found in [Supported M3U and XMLTV elements](#support
* **Group entries by title**: If multiple entries exist with matching titles, create a virtual folder to group them together.
* **Group entries by season**: If multiple entries exist with matching titles, try additionally grouping them in sub-folders representing seasons.
* **Include season and episode number in title**: Prepend the season and episode numbers to the title.
* **Use M3U Group name in path**: Select how to use the M3U group title in the path. Note that it will only be used if a single group name is provided. The options are:
- `Never` - Never use it.
- `Always append` - Always append it.
- `When no media-dir is present` - Only use the group title of the M3U when no media-dir is provided.
* **Force all M3U entries to be media**: Force the full playlist to be media, regardless of what tags are present. Since the introduction of multiple instances for PVR add-ons this option can be useful.
* **Include VODs as media**: Show VOD as recordings if enabled. If disabled only M3U entries with media attributes will be shown as PVR recordings.

### Timeshift
Expand Down
2 changes: 1 addition & 1 deletion pvr.iptvsimple/addon.xml.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon
id="pvr.iptvsimple"
version="21.2.1"
version="21.3.0"
name="IPTV Simple Client"
provider-name="nightik and Ross Nicholson">
<requires>@ADDON_DEPENDS@
Expand Down
5 changes: 5 additions & 0 deletions pvr.iptvsimple/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
v21.3.0
- Add settings options to add M3U group name to directory for media
- Add expert option to force the entire playlist to be Media. Useful now that multiple instances are supported
- Support custom groups for Media

v21.2.1
- Don't URL encode paths using resource:// or special:// protocols

Expand Down
20 changes: 20 additions & 0 deletions pvr.iptvsimple/resources/instance-settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,26 @@
</dependencies>
<control type="toggle" />
</setting>
<setting id="mediaM3UGroupPath" type="integer" parent="mediaEnabled" label="30156" help="30806">
<level>0</level>
<default>0</default>
<constraints>
<options>
<option label="30157">0</option> <!-- DONT_USE_GROUP_TITLE -->
<option label="30158">1</option> <!-- ALWAYS_APPEND_GROUP_TITLE -->
<option label="30159">2</option> <!-- USE_GROUP_TITLE_IF_NO_PATH -->
</options>
</constraints>
<control type="spinner" format="integer" />
</setting>
<setting id="mediaForcePlaylist" type="boolean" parent="mediaEnabled" label="30160" help="30807">
<level>2</level>
<default>false</default>
<dependencies>
<dependency type="enable" setting="mediaEnabled" operator="is">true</dependency>
</dependencies>
<control type="toggle" />
</setting>
<setting id="mediaVODAsRecordings" type="boolean" parent="mediaEnabled" label="30154" help="30804">
<level>2</level>
<default>true</default>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,32 @@ msgctxt "#30155"
msgid "Show Media as recordings"
msgstr ""

#empty strings from id 30156 to 30449
#. label: Media - mediaUseM3UGroupForGrouping
msgctxt "#30156"
msgid "Use M3U Group name in path"
msgstr ""

#. label-option: Media - mediaEnabled - IGNORE_GROUP_NAME
msgctxt "#30157"
msgid "Never"
msgstr ""

#. label-option: Media - mediaEnabled - ALWAYS_APPEND
msgctxt "#30158"
msgid "Always append"
msgstr ""

#. label-option: Media - mediaEnabled - ONLY_IF_EMPTY
msgctxt "#30159"
msgid "When no media-dir is present"
msgstr ""

#. label: Media - mediaForcePlaylist
msgctxt "#30160"
msgid "Force all M3U entries to be media"
msgstr ""

#empty strings from id 30161 to 30449

#. label: TV
msgctxt "#30450"
Expand Down Expand Up @@ -1068,4 +1093,14 @@ msgstr ""
#. label: Media - mediaEnabled
msgctxt "#30805"
msgid "If enabled, all IPTV media entries can be shown as PVR recordings. Otherwise, they appear as regular PVR channels."
msgstr ""

#. label: Media - mediaM3UGroupPath
msgctxt "#30806"
msgid "Select how to use the M3U group title in the path. Note that it will only be used if a single group name is provided. The options are: [B]Never[/B] - Never use it; [B]Always append[/B] - Always append it; [B]When no media-dir is present[/B] - Only use the group title of the M3U when no media-dir is provided."
msgstr ""

#. label: Media - mediaForcePlaylist
msgctxt "#30806"
msgid "Force the full playlist to be media, regardless of what tags are present. Since the introduction of multiple instances for PVR add-ons this option can be useful."
msgstr ""
8 changes: 7 additions & 1 deletion src/iptvsimple/InstanceSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,13 @@ void InstanceSettings::ReadSettings()
m_instance.CheckInstanceSettingEnum<EpgLogosMode>("logoFromEpg", m_epgLogosMode);
m_instance.CheckInstanceSettingBoolean("useLogosLocalPathOnly", m_useLocalLogosOnly);

// Media m_mediaEnabled
// Media
m_instance.CheckInstanceSettingBoolean("mediaEnabled", m_mediaEnabled);
m_instance.CheckInstanceSettingBoolean("mediaVODAsRecordings", m_showVodAsRecordings);
m_instance.CheckInstanceSettingBoolean("mediaGroupByTitle", m_groupMediaByTitle);
m_instance.CheckInstanceSettingBoolean("mediaGroupBySeason", m_groupMediaBySeason);
m_instance.CheckInstanceSettingEnum<MediaUseM3UGroupPathMode>("mediaM3UGroupPath", m_mediaUseM3UGroupPathMode);
m_instance.CheckInstanceSettingBoolean("mediaForcePlaylist", m_mediaForcePlaylist);
m_instance.CheckInstanceSettingBoolean("mediaTitleSeasonEpisode", m_includeShowInfoInMediaTitle);

// Timeshift
Expand Down Expand Up @@ -279,6 +281,10 @@ ADDON_STATUS InstanceSettings::SetSetting(const std::string& settingName, const
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_groupMediaBySeason, ADDON_STATUS_OK, ADDON_STATUS_OK);
else if (settingName == "mediaTitleSeasonEpisode")
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_includeShowInfoInMediaTitle, ADDON_STATUS_OK, ADDON_STATUS_OK);
else if (settingName == "mediaM3UGroupPath")
return SetEnumSetting<MediaUseM3UGroupPathMode, ADDON_STATUS>(settingName, settingValue, m_mediaUseM3UGroupPathMode, ADDON_STATUS_OK, ADDON_STATUS_OK);
else if (settingName == "mediaForcePlaylist")
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_mediaForcePlaylist, ADDON_STATUS_OK, ADDON_STATUS_OK);
else if (settingName == "mediaVODAsRecordings")
return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_showVodAsRecordings, ADDON_STATUS_OK, ADDON_STATUS_OK);
// Timeshift
Expand Down
13 changes: 13 additions & 0 deletions src/iptvsimple/InstanceSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ namespace iptvsimple
PREFER_XMLTV
};

enum class MediaUseM3UGroupPathMode
: int // same type as addon settings
{
IGNORE_GROUP_NAME = 0,
ALWAYS_APPEND,
ONLY_IF_EMPTY
};


enum class CatchupOverrideMode
: int // same type as addon settings
{
Expand Down Expand Up @@ -133,6 +142,8 @@ namespace iptvsimple
bool ShowVodAsRecordings() const { return m_showVodAsRecordings; }
bool GroupMediaByTitle() const { return m_groupMediaByTitle; }
bool GroupMediaBySeason() const { return m_groupMediaBySeason; }
const MediaUseM3UGroupPathMode& GetMediaUseM3UGroupPathMode() { return m_mediaUseM3UGroupPathMode; }
bool MediaForcePlaylist() const { return m_mediaForcePlaylist; }
bool IncludeShowInfoInMediaTitle() const { return m_includeShowInfoInMediaTitle; }

bool IsTimeshiftEnabled() const { return m_timeshiftEnabled; }
Expand Down Expand Up @@ -294,6 +305,8 @@ namespace iptvsimple
bool m_groupMediaByTitle = true;
bool m_groupMediaBySeason = true;
bool m_includeShowInfoInMediaTitle = false;
MediaUseM3UGroupPathMode m_mediaUseM3UGroupPathMode = MediaUseM3UGroupPathMode::IGNORE_GROUP_NAME;
bool m_mediaForcePlaylist = false;
bool m_showVodAsRecordings = true;

// Timeshift
Expand Down
21 changes: 20 additions & 1 deletion src/iptvsimple/Media.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,35 @@ int GenerateMediaEntryId(const char* providerName, const char* streamUrl)

} // unamed namespace

bool Media::AddMediaEntry(MediaEntry& mediaEntry)
bool Media::AddMediaEntry(MediaEntry& mediaEntry, std::vector<int>& groupIdList, ChannelGroups& channelGroups, bool channelHadGroups)
{
// If we have no groups set for this media check it that's ok before adding it.
// Note that TV is a proxy for Media. There is no concept of radio for media
if (m_settings->AllowTVChannelGroupsOnly() && groupIdList.empty())
return false;

std::string mediaEntryId = std::to_string(GenerateMediaEntryId(mediaEntry.GetProviderName().c_str(),
mediaEntry.GetStreamURL().c_str()));
mediaEntryId.append("-" + mediaEntry.GetDirectory() + mediaEntry.GetTitle());
mediaEntry.SetMediaEntryId(mediaEntryId);

// Media Ids must be unique
if (m_mediaIdMap.find(mediaEntryId) != m_mediaIdMap.end())
return false;

bool belongsToGroup = false;
for (int myGroupId : groupIdList)
{
if (channelGroups.GetChannelGroup(myGroupId) != nullptr)
belongsToGroup = true;
}


// We only care if a media entry belongs to a group if it had groups to begin with
// Note that a channel can have had groups but no have no groups valid currently.
if (!belongsToGroup && channelHadGroups)
return false;

m_media.emplace_back(mediaEntry);
m_mediaIdMap.insert({mediaEntryId, mediaEntry});

Expand Down
3 changes: 2 additions & 1 deletion src/iptvsimple/Media.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#pragma once

#include "ChannelGroups.h"
#include "data/MediaEntry.h"

#include <string>
Expand All @@ -26,7 +27,7 @@ namespace iptvsimple
const std::string GetMediaEntryURL(const kodi::addon::PVRRecording& mediaEntry);
const iptvsimple::data::MediaEntry* FindMediaEntry(const std::string& id, const std::string& displayName) const;

bool AddMediaEntry(iptvsimple::data::MediaEntry& entry);
bool AddMediaEntry(iptvsimple::data::MediaEntry& entry, std::vector<int>& groupIdList, iptvsimple::ChannelGroups& channelGroups, bool channelHadGroups);

std::vector<iptvsimple::data::MediaEntry>& GetMediaEntryList() { return m_media; }

Expand Down
21 changes: 18 additions & 3 deletions src/iptvsimple/PlaylistLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ bool PlaylistLoader::LoadPlayList()

isMediaEntry = line.find(MEDIA) != std::string::npos ||
line.find(MEDIA_DIR) != std::string::npos ||
line.find(MEDIA_SIZE) != std::string::npos;
line.find(MEDIA_SIZE) != std::string::npos ||
m_settings->MediaForcePlaylist();

const std::string groupNamesListString = ParseIntoChannel(line, tmpChannel, tmpMediaEntry, currentChannelGroupIdList, epgTimeShift, catchupCorrectionSecs, xeevCatchup);

Expand Down Expand Up @@ -203,7 +204,7 @@ bool PlaylistLoader::LoadPlayList()
entry.UpdateFrom(tmpChannel);
entry.SetStreamURL(line);

if (!m_media.AddMediaEntry(entry))
if (!m_media.AddMediaEntry(entry, currentChannelGroupIdList, m_channelGroups, channelHadGroups))
Logger::Log(LEVEL_DEBUG, "%s - Counld not add media entry as an entry with the same gnenerated unique ID already exists", __func__);

}
Expand Down Expand Up @@ -454,10 +455,24 @@ std::string PlaylistLoader::ParseIntoChannel(const std::string& line, Channel& c
if (!strMediaDir.empty())
mediaEntry.SetDirectory(strMediaDir);

std::string groupNames = ReadMarkerValue(infoLine, GROUP_NAME_MARKER);
auto& m3uGroupPathMode = m_settings->GetMediaUseM3UGroupPathMode();
if (m3uGroupPathMode != MediaUseM3UGroupPathMode::IGNORE_GROUP_NAME)
{
if (m3uGroupPathMode == MediaUseM3UGroupPathMode::ALWAYS_APPEND || strMediaDir.empty())
{
if (!groupNames.empty() && groupNames.find(';') == std::string::npos)
{
//A media entry directory will always end with a "/"
mediaEntry.SetDirectory(mediaEntry.GetDirectory() + groupNames);
}
}
}

if (!strMediaSize.empty())
mediaEntry.SetSizeInBytes(std::strtoll(strMediaSize.c_str(), nullptr, 10));

return ReadMarkerValue(infoLine, GROUP_NAME_MARKER);
return groupNames;
}

return "";
Expand Down
6 changes: 6 additions & 0 deletions src/iptvsimple/data/MediaEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ std::string FixPath(const std::string& path)

} // unamed namespace

void MediaEntry::SetDirectory(const std::string& value)
{
m_directory = FixPath(value);
}


void MediaEntry::UpdateTo(kodi::addon::PVRRecording& left, bool isInVirtualMediaEntryFolder, bool haveMediaTypes)
{
left.SetTitle(CreateTitle(m_title, m_seasonNumber, m_episodeNumber, m_settings));
Expand Down
2 changes: 1 addition & 1 deletion src/iptvsimple/data/MediaEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ namespace iptvsimple
void SetProviderUniqueId(int value) { m_providerUniqueId = value; }

const std::string& GetDirectory() const { return m_directory; }
void SetDirectory(const std::string& value) { m_directory = value; }
void SetDirectory(const std::string& value);

int64_t GetSizeInBytes() const { return m_sizeInBytes; }
void SetSizeInBytes(int64_t value) { m_sizeInBytes = value; }
Expand Down

0 comments on commit ab8002b

Please sign in to comment.