aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain CECCHETTO <cecchetto.sylvain@me.com>2020-06-11 11:54:01 +0200
committerSylvain CECCHETTO <cecchetto.sylvain@me.com>2020-08-26 17:11:38 +0200
commit3737c035232b31d0e9af7ea83e389d49e978cad3 (patch)
tree2c48167e470d5e32615a58fd155ba68b39e1583e
parente418ee4607c78d5012f27a0e8fd70cd1f0ab7c56 (diff)
[tvOS][TopShelf] Refactor code
-rw-r--r--cmake/scripts/darwin_embedded/ExtraTargets.cmake6
-rw-r--r--xbmc/platform/darwin/DarwinUtils.h2
-rw-r--r--xbmc/platform/darwin/DarwinUtils.mm52
-rw-r--r--xbmc/platform/darwin/ios-common/CMakeLists.txt2
-rw-r--r--xbmc/platform/darwin/ios-common/DarwinEmbedUtils.h16
-rw-r--r--xbmc/platform/darwin/ios-common/DarwinEmbedUtils.mm52
-rw-r--r--xbmc/platform/darwin/tvos/CMakeLists.txt2
-rw-r--r--xbmc/platform/darwin/tvos/TVOSTopShelf.h9
-rw-r--r--xbmc/platform/darwin/tvos/TVOSTopShelf.mm150
-rw-r--r--xbmc/platform/darwin/tvos/TopShelf/ServiceProvider.m124
-rw-r--r--xbmc/platform/darwin/tvos/TopShelf/ServiceProvider.mm123
-rw-r--r--xbmc/platform/darwin/tvos/tvosShared.h1
-rw-r--r--xbmc/platform/darwin/tvos/tvosShared.mm (renamed from xbmc/platform/darwin/tvos/tvosShared.m)30
-rw-r--r--xbmc/settings/SettingsComponent.cpp13
-rw-r--r--xbmc/utils/RecentlyAddedJob.cpp5
15 files changed, 311 insertions, 276 deletions
diff --git a/cmake/scripts/darwin_embedded/ExtraTargets.cmake b/cmake/scripts/darwin_embedded/ExtraTargets.cmake
index 2b9980a184..1b984f36b8 100644
--- a/cmake/scripts/darwin_embedded/ExtraTargets.cmake
+++ b/cmake/scripts/darwin_embedded/ExtraTargets.cmake
@@ -7,9 +7,11 @@ if(CORE_PLATFORM_NAME_LC STREQUAL tvos)
set(ENTITLEMENTS_OUT_PATH "${CMAKE_BINARY_DIR}/CMakeFiles/${TOPSHELF_EXTENSION_NAME}.dir/TopShelf.entitlements")
set(SOURCES
- ${TOPSHELF_DIR}/ServiceProvider.m
- ${TOPSHELF_DIR}/../tvosShared.m)
+ ${TOPSHELF_DIR}/../../ios-common/DarwinEmbedUtils.mm
+ ${TOPSHELF_DIR}/ServiceProvider.mm
+ ${TOPSHELF_DIR}/../tvosShared.mm)
set(HEADERS
+ ${TOPSHELF_DIR}/../../ios-common/DarwinEmbedUtils.h
${TOPSHELF_DIR}/ServiceProvider.h
${TOPSHELF_DIR}/../tvosShared.h)
add_executable(${TOPSHELF_EXTENSION_NAME} MACOSX_BUNDLE ${SOURCES} ${HEADERS})
diff --git a/xbmc/platform/darwin/DarwinUtils.h b/xbmc/platform/darwin/DarwinUtils.h
index 4f3db3557d..be2cb51dc0 100644
--- a/xbmc/platform/darwin/DarwinUtils.h
+++ b/xbmc/platform/darwin/DarwinUtils.h
@@ -24,8 +24,6 @@ public:
static const char* GetVersionString();
static std::string GetFrameworkPath(bool forPython);
static int GetExecutablePath(char* path, size_t *pathsize);
- static const char *GetAppRootFolder(void);
- static bool IsIosSandboxed(void);
static void SetScheduling(bool realtime);
static bool CFStringRefToString(CFStringRef source, std::string& destination);
static bool CFStringRefToUTF8String(CFStringRef source, std::string& destination);
diff --git a/xbmc/platform/darwin/DarwinUtils.mm b/xbmc/platform/darwin/DarwinUtils.mm
index 8f9cd57e19..0b4178ba8d 100644
--- a/xbmc/platform/darwin/DarwinUtils.mm
+++ b/xbmc/platform/darwin/DarwinUtils.mm
@@ -140,58 +140,6 @@ int CDarwinUtils::GetExecutablePath(char* path, size_t *pathsize)
return 0;
}
-const char* CDarwinUtils::GetAppRootFolder(void)
-{
- static std::string rootFolder;
- static std::once_flag flag;
- std::call_once(flag, []
- {
- if (IsIosSandboxed())
- {
-#ifdef TARGET_DARWIN_TVOS
- // writing to Documents is prohibited, more info:
- // https://developer.apple.com/library/archive/documentation/General/Conceptual/AppleTV_PG/index.html#//apple_ref/doc/uid/TP40015241-CH12-SW5
- // https://forums.developer.apple.com/thread/89008
- rootFolder = "Library/Caches";
-#else
- // when we are sandbox make documents our root
- // so that user can access everything he needs
- // via itunes sharing
- rootFolder = "Documents";
-#endif
- }
- else
- {
- rootFolder = "Library/Preferences";
- }
- });
- return rootFolder.c_str();
-}
-
-bool CDarwinUtils::IsIosSandboxed(void)
-{
- static bool ret = false;
- static std::once_flag flag;
- std::call_once(flag, [] {
- auto executablePath = getExecutablePath();
- auto sandboxPrefixPaths = {
- // since iOS later than 9.0.2 but before 9.3.5
- @"/var/containers/Bundle/",
- // since iOS 13
- @"/private/var/containers/Bundle/",
- };
- for (auto prefixPath : sandboxPrefixPaths)
- {
- if ([executablePath hasPrefix:prefixPath])
- {
- ret = true;
- break;
- }
- }
- });
- return ret;
-}
-
void CDarwinUtils::SetScheduling(bool realtime)
{
int policy;
diff --git a/xbmc/platform/darwin/ios-common/CMakeLists.txt b/xbmc/platform/darwin/ios-common/CMakeLists.txt
index 49ce23c93f..4e6241198b 100644
--- a/xbmc/platform/darwin/ios-common/CMakeLists.txt
+++ b/xbmc/platform/darwin/ios-common/CMakeLists.txt
@@ -3,6 +3,7 @@ set(SOURCES AnnounceReceiver.mm
DarwinEmbedKeyboard.mm
DarwinEmbedKeyboardView.mm
DarwinEmbedNowPlayingInfoManager.mm
+ DarwinEmbedUtils.mm
DarwinNSUserDefaults.mm
NSData+GZIP.m)
@@ -11,6 +12,7 @@ set(HEADERS AnnounceReceiver.h
DarwinEmbedKeyboard.h
DarwinEmbedKeyboardView.h
DarwinEmbedNowPlayingInfoManager.h
+ DarwinEmbedUtils.h
DarwinNSUserDefaults.h
NSData+GZIP.h)
diff --git a/xbmc/platform/darwin/ios-common/DarwinEmbedUtils.h b/xbmc/platform/darwin/ios-common/DarwinEmbedUtils.h
new file mode 100644
index 0000000000..7402970d5f
--- /dev/null
+++ b/xbmc/platform/darwin/ios-common/DarwinEmbedUtils.h
@@ -0,0 +1,16 @@
+/*
+* Copyright (C) 2010-2020 Team Kodi
+* This file is part of Kodi - https://kodi.tv
+*
+* SPDX-License-Identifier: GPL-2.0-or-later
+* See LICENSES/README.md for more information.
+*/
+
+#pragma once
+
+class CDarwinEmbedUtils
+{
+public:
+ static const char* GetAppRootFolder(void);
+ static bool IsIosSandboxed(void);
+};
diff --git a/xbmc/platform/darwin/ios-common/DarwinEmbedUtils.mm b/xbmc/platform/darwin/ios-common/DarwinEmbedUtils.mm
new file mode 100644
index 0000000000..f2fa674e22
--- /dev/null
+++ b/xbmc/platform/darwin/ios-common/DarwinEmbedUtils.mm
@@ -0,0 +1,52 @@
+/*
+* Copyright (C) 2010-2020 Team Kodi
+* This file is part of Kodi - https://kodi.tv
+*
+* SPDX-License-Identifier: GPL-2.0-or-later
+* See LICENSES/README.md for more information.
+*/
+
+#import "DarwinEmbedUtils.h"
+
+#include <mutex>
+#include <string>
+
+#import <Foundation/Foundation.h>
+
+const char* CDarwinEmbedUtils::GetAppRootFolder(void)
+{
+ static std::string rootFolder;
+ static std::once_flag flag;
+ std::call_once(flag, [] {
+ if (IsIosSandboxed())
+ {
+#ifdef TARGET_DARWIN_TVOS
+ // writing to Documents is prohibited, more info:
+ // https://developer.apple.com/library/archive/documentation/General/Conceptual/AppleTV_PG/index.html#//apple_ref/doc/uid/TP40015241-CH12-SW5
+ // https://forums.developer.apple.com/thread/89008
+ rootFolder = "Library/Caches";
+#else
+ // when we are sandbox make documents our root
+ // so that user can access everything he needs
+ // via itunes sharing
+ rootFolder = "Documents";
+#endif
+ }
+ else
+ {
+ rootFolder = "Library/Preferences";
+ }
+ });
+ return rootFolder.c_str();
+}
+
+bool CDarwinEmbedUtils::IsIosSandboxed(void)
+{
+ static bool ret;
+ static std::once_flag flag;
+ std::call_once(flag, [] {
+ auto const sandboxPrefixPath = @"/private/var/containers/Bundle/";
+ ret = [NSBundle.mainBundle.executablePath hasPrefix:sandboxPrefixPath];
+ });
+ return ret;
+}
diff --git a/xbmc/platform/darwin/tvos/CMakeLists.txt b/xbmc/platform/darwin/tvos/CMakeLists.txt
index 099511dd07..8500d04c06 100644
--- a/xbmc/platform/darwin/tvos/CMakeLists.txt
+++ b/xbmc/platform/darwin/tvos/CMakeLists.txt
@@ -3,7 +3,7 @@ set(SOURCES PreflightHandler.mm
TVOSEAGLView.mm
TVOSKeyboardView.mm
TVOSSettingsHandler.mm
- tvosShared.m
+ tvosShared.mm
TVOSTopShelf.mm
XBMCController.mm)
diff --git a/xbmc/platform/darwin/tvos/TVOSTopShelf.h b/xbmc/platform/darwin/tvos/TVOSTopShelf.h
index ee5c244a5e..06f8643571 100644
--- a/xbmc/platform/darwin/tvos/TVOSTopShelf.h
+++ b/xbmc/platform/darwin/tvos/TVOSTopShelf.h
@@ -11,12 +11,19 @@
#include "FileItem.h"
#include "threads/CriticalSection.h"
+typedef enum
+{
+ MOVIES = 0,
+ TV_SHOWS = 1
+} TVOSTopShelfItemsCategory;
+
+
class CTVOSTopShelf
{
public:
static CTVOSTopShelf& GetInstance();
void RunTopShelf();
- void SetTopShelfItems(CFileItemList& movies, CFileItemList& tv);
+ void SetTopShelfItems(CFileItemList& items, TVOSTopShelfItemsCategory category);
void HandleTopShelfUrl(const std::string& url, const bool run);
private:
diff --git a/xbmc/platform/darwin/tvos/TVOSTopShelf.mm b/xbmc/platform/darwin/tvos/TVOSTopShelf.mm
index 852f40d2e9..50dae8f508 100644
--- a/xbmc/platform/darwin/tvos/TVOSTopShelf.mm
+++ b/xbmc/platform/darwin/tvos/TVOSTopShelf.mm
@@ -28,6 +28,8 @@
#include "video/windows/GUIWindowVideoBase.h"
#include "video/windows/GUIWindowVideoNav.h"
+#include "platform/darwin/ios-common/DarwinEmbedUtils.h"
+
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <mach/mach_host.h>
@@ -46,119 +48,137 @@ CTVOSTopShelf& CTVOSTopShelf::GetInstance()
return sTopShelf;
}
-void CTVOSTopShelf::SetTopShelfItems(CFileItemList& movies, CFileItemList& tv)
+void CTVOSTopShelf::SetTopShelfItems(CFileItemList& items, TVOSTopShelfItemsCategory category)
{
@autoreleasepool
{
+ // Retrieve store URL
auto storeUrl = [tvosShared getSharedURL];
if (!storeUrl)
return;
-
storeUrl = [storeUrl URLByAppendingPathComponent:@"RA" isDirectory:YES];
- const BOOL isJailbroken = [tvosShared isJailbroken];
- CLog::Log(LOGDEBUG, "TopShelf: using shared path {} (jailbroken: {})", storeUrl.path.UTF8String,
- isJailbroken ? "yes" : "no");
- auto sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:[tvosShared getSharedID]];
- auto sharedDictJailbreak = isJailbroken ? [[NSMutableDictionary alloc] initWithCapacity:2 + 2]
- : nil; // for jailbroken devices
+ const auto isSandboxed = CDarwinEmbedUtils::IsIosSandboxed();
+ CLog::Log(LOGDEBUG, "[TopShelf] (sandboxed: {}) Use storeUrl: {}", isSandboxed ? "yes" : "no",
+ storeUrl.path.UTF8String);
// store all old thumbs in array
auto fileManager = NSFileManager.defaultManager;
auto filePaths =
[NSMutableSet setWithArray:[fileManager contentsOfDirectoryAtPath:storeUrl.path error:nil]];
std::string raPath = storeUrl.path.UTF8String;
- CVideoThumbLoader thumbLoader;
+ // Shared dicts (if we are sandboxed we use sharedDefaults, else we use sharedJailbreak)
+ auto sharedDefaults =
+ isSandboxed ? [[NSUserDefaults alloc] initWithSuiteName:[tvosShared getSharedID]] : nil;
+ auto sharedJailbreak = isSandboxed ? nil : [[NSMutableDictionary alloc] initWithCapacity:2];
+
+ // Function used to add category items in TopShelf shared dict
+ CVideoThumbLoader thumbLoader;
auto fillSharedDicts =
- [&](CFileItemList& videoItems, NSString* videosKey, NSString* videosTitleKey,
- uint32_t titleStringCode,
+ [&](CFileItemList& items, NSString* categoryKey, uint32_t categoryTitleCode,
std::function<std::string(CFileItemPtr videoItem)> getThumbnailForItem,
std::function<std::string(CFileItemPtr videoItem)> getTitleForItem) {
- if (videoItems.Size() <= 0)
+ if (items.Size() <= 0)
{
- // cleanup if there is no RA
- [sharedDefaults removeObjectForKey:videosKey];
- [sharedDefaults removeObjectForKey:videosTitleKey];
+ // If there is no item in this category, remove this dict from sharedDefaults
+ [sharedDefaults removeObjectForKey:categoryKey];
return;
}
- const int topShelfSize = std::min(videoItems.Size(), MaxItems);
- auto videosArray = [NSMutableArray arrayWithCapacity:topShelfSize];
- for (int i = 0; i < topShelfSize; ++i)
+ // Create dict for this category
+ auto categoryDict = [NSMutableDictionary dictionaryWithCapacity:2];
+
+ // Save category title in dict
+ categoryDict[@"categoryTitle"] = @(g_localizeStrings.Get(categoryTitleCode).c_str());
+
+ // Create an array to store each category item
+ const int categorySize = std::min(items.Size(), MaxItems);
+ auto categoryItems = [NSMutableArray arrayWithCapacity:categorySize];
+ for (int i = 0; i < categorySize; ++i)
{
@autoreleasepool
{
- auto videoItem = videoItems.Get(i);
- if (!videoItem->HasArt("thumb"))
- thumbLoader.LoadItem(videoItem.get());
+ auto item = items.Get(i);
+ if (!item->HasArt("thumb"))
+ thumbLoader.LoadItem(item.get());
- auto thumbnailPath = getThumbnailForItem(videoItem);
- auto fileName = std::to_string(videoItem->GetVideoInfoTag()->m_iDbId) +
+ auto thumbnailPath = getThumbnailForItem(item);
+ auto fileName = std::to_string(item->GetVideoInfoTag()->m_iDbId) +
URIUtils::GetFileName(thumbnailPath);
auto destPath = URIUtils::AddFileToFolder(raPath, fileName);
if (!XFILE::CFile::Exists(destPath))
XFILE::CFile::Copy(thumbnailPath, destPath);
else
{
- // remove from array so it doesnt get deleted at the end
+ // Remove from array so it doesn't get deleted at the end
[filePaths removeObject:@(fileName.c_str())];
}
- auto title = getTitleForItem(videoItem);
- CLog::Log(LOGDEBUG, "TopShelf: - adding video to '{}' array: {}",
- videosKey.UTF8String, title.c_str());
- [videosArray addObject:@{
- @"title" : @(title.c_str()),
+ auto itemTitle = getTitleForItem(item);
+ CLog::Log(LOGDEBUG, "[TopShelf] Adding item '{}' in category '{}'", itemTitle.c_str(),
+ categoryKey.UTF8String);
+ [categoryItems addObject:@{
+ @"title" : @(itemTitle.c_str()),
@"thumb" : @(fileName.c_str()),
- @"url" : @(Base64::Encode(videoItem->GetVideoInfoTag()->GetPath()).c_str())
+ @"url" : @(Base64::Encode(item->GetVideoInfoTag()->GetPath()).c_str())
}];
}
}
- [sharedDefaults setObject:videosArray forKey:videosKey];
- sharedDictJailbreak[videosKey] = videosArray;
- auto tvTitle = @(g_localizeStrings.Get(titleStringCode).c_str());
- [sharedDefaults setObject:tvTitle forKey:videosTitleKey];
- sharedDictJailbreak[videosTitleKey] = tvTitle;
+ // Store category items array in category dict
+ categoryDict[@"categoryItems"] = categoryItems;
+
+ // Store category dict in shared dict
+ [sharedDefaults setObject:categoryDict forKey:categoryKey];
+ sharedJailbreak[categoryKey] = categoryDict;
};
- fillSharedDicts(movies, @"movies", @"moviesTitle", 20386,
- [](CFileItemPtr videoItem) {
- if (videoItem->HasArt("poster"))
- {
- return videoItem->GetArt("poster");
- }
- else
- return videoItem->GetArt("thumb");
- },
- [](CFileItemPtr videoItem) { return videoItem->GetLabel(); });
-
- CVideoDatabase videoDb;
- videoDb.Open();
- fillSharedDicts(tv, @"tv", @"tvTitle", 20387,
- [&videoDb](CFileItemPtr videoItem) {
- int season = videoItem->GetVideoInfoTag()->m_iIdSeason;
- return season > 0 ? videoDb.GetArtForItem(season, MediaTypeSeason, "poster")
- : std::string{};
- },
- [](CFileItemPtr videoItem) {
- return StringUtils::Format(
- "%s s%02de%02d", videoItem->GetVideoInfoTag()->m_strShowTitle.c_str(),
- videoItem->GetVideoInfoTag()->m_iSeason,
- videoItem->GetVideoInfoTag()->m_iEpisode);
- });
- videoDb.Close();
-
- // remove unused thumbs from cache folder
+
+ // Based on category type, add items in TopShelf shared dict
+ switch (category)
+ {
+ case TVOSTopShelfItemsCategory::MOVIES:
+ fillSharedDicts(
+ items, @"movies", 20386,
+ [](CFileItemPtr videoItem) {
+ if (videoItem->HasArt("poster"))
+ return videoItem->GetArt("poster");
+ else
+ return videoItem->GetArt("thumb");
+ },
+ [](CFileItemPtr videoItem) { return videoItem->GetLabel(); });
+ break;
+ case TVOSTopShelfItemsCategory::TV_SHOWS:
+ CVideoDatabase videoDb;
+ videoDb.Open();
+ fillSharedDicts(
+ items, @"tvshows", 20387,
+ [&videoDb](CFileItemPtr videoItem) {
+ int season = videoItem->GetVideoInfoTag()->m_iIdSeason;
+ return season > 0 ? videoDb.GetArtForItem(season, MediaTypeSeason, "poster")
+ : std::string{};
+ },
+ [](CFileItemPtr videoItem) {
+ return StringUtils::Format("%s s%02de%02d",
+ videoItem->GetVideoInfoTag()->m_strShowTitle.c_str(),
+ videoItem->GetVideoInfoTag()->m_iSeason,
+ videoItem->GetVideoInfoTag()->m_iEpisode);
+ });
+ videoDb.Close();
+ break;
+ }
+
+ // Remove unused thumbs from cache folder
NSString* strFiles;
for (strFiles in filePaths)
[fileManager removeItemAtURL:[storeUrl URLByAppendingPathComponent:strFiles isDirectory:NO]
error:nil];
- [sharedDictJailbreak writeToURL:[storeUrl URLByAppendingPathComponent:@"shared.dict"]
- atomically:YES];
+ // Synchronize shared dict
[sharedDefaults synchronize];
+ [sharedJailbreak writeToURL:[storeUrl URLByAppendingPathComponent:@"shared.dict"]
+ atomically:YES];
}
}
diff --git a/xbmc/platform/darwin/tvos/TopShelf/ServiceProvider.m b/xbmc/platform/darwin/tvos/TopShelf/ServiceProvider.m
deleted file mode 100644
index 3277db4e49..0000000000
--- a/xbmc/platform/darwin/tvos/TopShelf/ServiceProvider.m
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2015 Team MrMC
- * https://github.com/MrMC
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with MrMC; see the file COPYING. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#import "ServiceProvider.h"
-
-#import "../tvosShared.h"
-
-@implementation ServiceProvider
-
-#pragma mark - TVTopShelfProvider protocol
-
-- (TVTopShelfContentStyle)topShelfStyle
-{
- return TVTopShelfContentStyleSectioned;
-}
-
-- (NSArray<TVContentItem*>*)topShelfItems
-{
- __auto_type storeUrl = [tvosShared getSharedURL];
- if (!storeUrl)
- return @[];
-
- __auto_type const sharedID = [tvosShared getSharedID];
- __auto_type const shared = [[NSUserDefaults alloc] initWithSuiteName:sharedID];
- __auto_type topShelfItems = [[NSMutableArray alloc] init];
- __auto_type wrapperIdentifier =
- [[TVContentIdentifier alloc] initWithIdentifier:@"shelf-wrapper" container:nil];
-
- NSArray* movieArray = nil;
- NSArray* tvArray = nil;
- NSDictionary* sharedDict = nil;
-
- if ([tvosShared isJailbroken])
- {
- __auto_type sharedDictUrl =
- [storeUrl URLByAppendingPathComponent:@"shared.dict" isDirectory:NO];
- sharedDict = [NSDictionary dictionaryWithContentsOfFile:[sharedDictUrl path]];
-
- movieArray = [sharedDict valueForKey:@"movies"];
- tvArray = [sharedDict valueForKey:@"tv"];
- }
- else
- {
- movieArray = [shared objectForKey:@"movies"];
- tvArray = [shared valueForKey:@"tv"];
- }
-
- __auto_type mainAppBundle = [tvosShared mainAppBundle];
- __auto_type kodiUrlScheme = @"kodi"; // fallback value
- NSDictionary* dic;
- for (dic in [mainAppBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"])
- {
- if ([dic[@"CFBundleURLName"] isEqualToString:mainAppBundle.bundleIdentifier])
- {
- kodiUrlScheme = dic[@"CFBundleURLSchemes"][0];
- break;
- }
- }
-
- storeUrl = [storeUrl URLByAppendingPathComponent:@"RA" isDirectory:YES];
- __auto_type contentItemsFrom = ^NSArray<TVContentItem*>*(NSArray* videosArray)
- {
- NSMutableArray<TVContentItem*>* contentItems =
- [[NSMutableArray alloc] initWithCapacity:videosArray.count];
- NSDictionary* videoDict;
- for (videoDict in videosArray)
- {
- __auto_type identifier =
- [[TVContentIdentifier alloc] initWithIdentifier:@"VOD" container:wrapperIdentifier];
- __auto_type contentItem = [[TVContentItem alloc] initWithContentIdentifier:identifier];
-
- [contentItem
- setImageURL:[storeUrl URLByAppendingPathComponent:[videoDict valueForKey:@"thumb"]
- isDirectory:NO]
- forTraits:TVContentItemImageTraitScreenScale1x];
- contentItem.imageShape = TVContentItemImageShapePoster;
- contentItem.title = [videoDict valueForKey:@"title"];
- NSString* url = [videoDict valueForKey:@"url"];
- contentItem.displayURL = [NSURL
- URLWithString:[NSString stringWithFormat:@"%@://display/movie/%@", kodiUrlScheme, url]];
- contentItem.playURL = [NSURL
- URLWithString:[NSString stringWithFormat:@"%@://play/movie/%@", kodiUrlScheme, url]];
- [contentItems addObject:contentItem];
- }
- return contentItems;
- };
-
- if ([movieArray count] > 0)
- {
- __auto_type itemMovie = [[TVContentItem alloc] initWithContentIdentifier:wrapperIdentifier];
- itemMovie.title = [(sharedDict ?: shared) valueForKey:@"moviesTitle"];
- itemMovie.topShelfItems = contentItemsFrom(movieArray);
- [topShelfItems addObject:itemMovie];
- }
-
- if ([tvArray count] > 0)
- {
- __auto_type itemTv = [[TVContentItem alloc] initWithContentIdentifier:wrapperIdentifier];
- itemTv.title = [(sharedDict ?: shared) valueForKey:@"tvTitle"];
- itemTv.topShelfItems = contentItemsFrom(tvArray);
- [topShelfItems addObject:itemTv];
- }
-
- return topShelfItems;
-}
-
-@end
diff --git a/xbmc/platform/darwin/tvos/TopShelf/ServiceProvider.mm b/xbmc/platform/darwin/tvos/TopShelf/ServiceProvider.mm
new file mode 100644
index 0000000000..fef201dfda
--- /dev/null
+++ b/xbmc/platform/darwin/tvos/TopShelf/ServiceProvider.mm
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 Team MrMC
+ * https://github.com/MrMC
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MrMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import "ServiceProvider.h"
+
+#import "../tvosShared.h"
+
+#include "platform/darwin/ios-common/DarwinEmbedUtils.h"
+
+@implementation ServiceProvider
+
+#pragma mark - TVTopShelfProvider protocol
+
+- (TVTopShelfContentStyle)topShelfStyle
+{
+ return TVTopShelfContentStyleSectioned;
+}
+
+- (NSArray<TVContentItem*>*)topShelfItems
+{
+ // Retrieve store URL
+ auto storeUrl = [tvosShared getSharedURL];
+ if (!storeUrl)
+ return @[];
+ storeUrl = [storeUrl URLByAppendingPathComponent:@"RA" isDirectory:YES];
+
+
+ // Retrieve shared dict
+ NSDictionary* sharedDict;
+ if (CDarwinEmbedUtils::IsIosSandboxed())
+ {
+ auto const sharedID = [tvosShared getSharedID];
+ auto const shared = [[NSUserDefaults alloc] initWithSuiteName:sharedID];
+ sharedDict = shared.dictionaryRepresentation;
+ }
+ else
+ {
+ auto sharedDictUrl = [storeUrl URLByAppendingPathComponent:@"shared.dict"
+ isDirectory:NO];
+ sharedDict = [NSDictionary dictionaryWithContentsOfFile:[sharedDictUrl path]];
+ }
+
+
+ // Retrieve Kodi URL Scheme
+ auto const mainAppBundle = [tvosShared mainAppBundle];
+ auto kodiUrlScheme = @"kodi"; // fallback value
+ for (NSDictionary* dic in [mainAppBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"])
+ {
+ if ([dic[@"CFBundleURLName"] isEqualToString:mainAppBundle.bundleIdentifier])
+ {
+ kodiUrlScheme = dic[@"CFBundleURLSchemes"][0];
+ break;
+ }
+ }
+
+ auto wrapperIdentifier = [[TVContentIdentifier alloc] initWithIdentifier:@"shelf-wrapper"
+ container:nil];
+
+
+ // Function to create a TVContentItem array from an array of items (a category)
+ auto contentItemsFrom = ^NSArray<TVContentItem*>*(NSArray* categoryItems)
+ {
+ NSMutableArray<TVContentItem*>* contentItems =
+ [[NSMutableArray alloc] initWithCapacity:categoryItems.count];
+ for (NSDictionary* item in categoryItems)
+ {
+ auto identifier = [[TVContentIdentifier alloc] initWithIdentifier:@"VOD"
+ container:wrapperIdentifier];
+ auto contentItem = [[TVContentItem alloc] initWithContentIdentifier:identifier];
+
+ [contentItem setImageURL:[storeUrl URLByAppendingPathComponent:item[@"thumb"] isDirectory:NO]
+ forTraits:TVContentItemImageTraitScreenScale1x];
+ contentItem.imageShape = TVContentItemImageShapePoster;
+ contentItem.title = item[@"title"];
+ NSString* url = item[@"url"];
+ contentItem.displayURL = [NSURL
+ URLWithString:[NSString stringWithFormat:@"%@://display/movie/%@", kodiUrlScheme, url]];
+ contentItem.playURL = [NSURL
+ URLWithString:[NSString stringWithFormat:@"%@://play/movie/%@", kodiUrlScheme, url]];
+ [contentItems addObject:contentItem];
+ }
+ return contentItems;
+ };
+
+ // Add each category to TopShelf
+ auto topShelfItems = [[NSMutableArray alloc] init];
+
+ [sharedDict enumerateKeysAndObjectsUsingBlock:^(NSString* categoryKey, id categoryDict, BOOL *stop) {
+ if (![categoryDict isKindOfClass:[NSDictionary class]])
+ return;
+ NSArray* categoryItems = categoryDict[@"categoryItems"];
+ if (!categoryItems)
+ return;
+ if (categoryItems.count == 0)
+ return;
+
+ auto categoryContent = [[TVContentItem alloc] initWithContentIdentifier:wrapperIdentifier];
+ categoryContent.title = categoryDict[@"categoryTitle"];
+ categoryContent.topShelfItems = contentItemsFrom(categoryItems);
+ [topShelfItems addObject:categoryContent];
+ }];
+
+ return topShelfItems;
+}
+
+@end
diff --git a/xbmc/platform/darwin/tvos/tvosShared.h b/xbmc/platform/darwin/tvos/tvosShared.h
index dd9bbc5279..093ed184e0 100644
--- a/xbmc/platform/darwin/tvos/tvosShared.h
+++ b/xbmc/platform/darwin/tvos/tvosShared.h
@@ -11,6 +11,5 @@
@interface tvosShared : NSObject
+ (NSString*)getSharedID;
+ (NSURL*)getSharedURL;
-+ (BOOL)isJailbroken;
+ (NSBundle*)mainAppBundle;
@end
diff --git a/xbmc/platform/darwin/tvos/tvosShared.m b/xbmc/platform/darwin/tvos/tvosShared.mm
index b194dd9f48..14accc944a 100644
--- a/xbmc/platform/darwin/tvos/tvosShared.m
+++ b/xbmc/platform/darwin/tvos/tvosShared.mm
@@ -8,6 +8,8 @@
#import "tvosShared.h"
+#include "platform/darwin/ios-common/DarwinEmbedUtils.h"
+
@implementation tvosShared
+ (NSString*)getSharedID
@@ -18,34 +20,20 @@
+ (NSURL*)getSharedURL
{
NSString* sharedID = [self getSharedID];
- if ([self isJailbroken])
- return [[NSURL fileURLWithPath:@"/var/mobile/Library/Caches"]
- URLByAppendingPathComponent:sharedID];
- else
+ if (CDarwinEmbedUtils::IsIosSandboxed())
{
NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* sharedUrl = [fileManager containerURLForSecurityApplicationGroupIdentifier:sharedID];
+ // e.g. /private/var/mobile/Containers/Shared/AppGroup/32B9DA1F-3B1F-4DBC-8326-ABB08BF16EC9/
sharedUrl = [sharedUrl URLByAppendingPathComponent:@"Library" isDirectory:YES];
sharedUrl = [sharedUrl URLByAppendingPathComponent:@"Caches" isDirectory:YES];
return sharedUrl;
}
-}
-
-+ (BOOL)IsTVOSSandboxed
-{
- // @todo merge with CDarwinUtils::IsIosSandboxed
- static BOOL ret;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- // we re NOT sandboxed if we are installed in /var/mobile/Applications with greeng0blin jailbreak
- ret = ![[self mainAppBundle].bundlePath containsString:@"/var/mobile/Applications/"];
- });
- return ret;
-}
-
-+ (BOOL)isJailbroken
-{
- return ![self IsTVOSSandboxed];
+ else
+ {
+ return [[NSURL fileURLWithPath:@"/var/mobile/Library/Caches"]
+ URLByAppendingPathComponent:sharedID];
+ }
}
+ (NSBundle*)mainAppBundle
diff --git a/xbmc/settings/SettingsComponent.cpp b/xbmc/settings/SettingsComponent.cpp
index 5d1a4d186c..4fb51ca521 100644
--- a/xbmc/settings/SettingsComponent.cpp
+++ b/xbmc/settings/SettingsComponent.cpp
@@ -17,7 +17,7 @@
#include "filesystem/Directory.h"
#include "filesystem/SpecialProtocol.h"
#ifdef TARGET_DARWIN_EMBEDDED
-#include "platform/darwin/DarwinUtils.h"
+#include "platform/darwin/ios-common/DarwinEmbedUtils.h"
#endif
#ifdef TARGET_WINDOWS
#include "platform/Environment.h"
@@ -304,8 +304,10 @@ bool CSettingsComponent::InitDirectoriesOSX(bool bPlatformDirectories)
CSpecialProtocol::SetXBMCPath(appPath);
#if defined(TARGET_DARWIN_EMBEDDED)
std::string appName = CCompileInfo::GetAppName();
- CSpecialProtocol::SetHomePath(userHome + "/" + CDarwinUtils::GetAppRootFolder() + "/" + appName);
- CSpecialProtocol::SetMasterProfilePath(userHome + "/" + CDarwinUtils::GetAppRootFolder() + "/" + appName + "/userdata");
+ CSpecialProtocol::SetHomePath(userHome + "/" + CDarwinEmbedUtils::GetAppRootFolder() + "/" +
+ appName);
+ CSpecialProtocol::SetMasterProfilePath(userHome + "/" + CDarwinEmbedUtils::GetAppRootFolder() +
+ "/" + appName + "/userdata");
#else
std::string appName = CCompileInfo::GetAppName();
CSpecialProtocol::SetHomePath(userHome + "/Library/Application Support/" + appName);
@@ -316,7 +318,8 @@ bool CSettingsComponent::InitDirectoriesOSX(bool bPlatformDirectories)
StringUtils::ToLower(dotLowerAppName);
// location for temp files
#if defined(TARGET_DARWIN_EMBEDDED)
- std::string strTempPath = URIUtils::AddFileToFolder(userHome, std::string(CDarwinUtils::GetAppRootFolder()) + "/" + appName + "/temp");
+ std::string strTempPath = URIUtils::AddFileToFolder(
+ userHome, std::string(CDarwinEmbedUtils::GetAppRootFolder()) + "/" + appName + "/temp");
#else
std::string strTempPath = URIUtils::AddFileToFolder(userHome, dotLowerAppName + "/");
XFILE::CDirectory::Create(strTempPath);
@@ -326,7 +329,7 @@ bool CSettingsComponent::InitDirectoriesOSX(bool bPlatformDirectories)
// xbmc.log file location
#if defined(TARGET_DARWIN_EMBEDDED)
- strTempPath = userHome + "/" + std::string(CDarwinUtils::GetAppRootFolder());
+ strTempPath = userHome + "/" + std::string(CDarwinEmbedUtils::GetAppRootFolder());
#else
strTempPath = userHome + "/Library/Logs";
#endif
diff --git a/xbmc/utils/RecentlyAddedJob.cpp b/xbmc/utils/RecentlyAddedJob.cpp
index b45fadeb46..b6374fc6a8 100644
--- a/xbmc/utils/RecentlyAddedJob.cpp
+++ b/xbmc/utils/RecentlyAddedJob.cpp
@@ -145,8 +145,9 @@ bool CRecentlyAddedJob::UpdateVideo()
}
#if defined(TARGET_DARWIN_TVOS)
- // send recently added Movies and TvShows to TopShelf
- CTVOSTopShelf::GetInstance().SetTopShelfItems(items, TVShowItems);
+ // Add recently added Movies and TvShows items on tvOS Kodi TopShelf
+ CTVOSTopShelf::GetInstance().SetTopShelfItems(items, TVOSTopShelfItemsCategory::MOVIES);
+ CTVOSTopShelf::GetInstance().SetTopShelfItems(TVShowItems, TVOSTopShelfItemsCategory::TV_SHOWS);
#endif
i = 0;