Merge pull request #279 from palana/sparkle-update
Add option to use Sparkle for updates
This commit is contained in:
commit
daf2b02c73
@ -50,6 +50,20 @@ elseif(APPLE)
|
|||||||
set(obs_PLATFORM_LIBRARIES ${APPKIT_LIBRARIES})
|
set(obs_PLATFORM_LIBRARIES ${APPKIT_LIBRARIES})
|
||||||
|
|
||||||
add_definitions(-fobjc-arc)
|
add_definitions(-fobjc-arc)
|
||||||
|
|
||||||
|
option(ENABLE_SPARKLE_UPDATER "Enables updates via the Sparkle framework (don't forget to update the Info.plist for your .app)" OFF)
|
||||||
|
if(ENABLE_SPARKLE_UPDATER)
|
||||||
|
find_library(SPARKLE Sparkle)
|
||||||
|
include_directories(${SPARKLE})
|
||||||
|
set(obs_PLATFORM_SOURCES
|
||||||
|
${obs_PLATFORM_SOURCES}
|
||||||
|
sparkle-updater.mm)
|
||||||
|
set(obs_PLATFORM_LIBRARIES
|
||||||
|
${obs_PLATFORM_LIBRARIES}
|
||||||
|
${SPARKLE})
|
||||||
|
add_definitions(-DUPDATE_SPARKLE=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
find_package(Qt5X11Extras REQUIRED)
|
find_package(Qt5X11Extras REQUIRED)
|
||||||
|
|
||||||
|
128
obs/sparkle-updater.mm
Normal file
128
obs/sparkle-updater.mm
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <Sparkle/Sparkle.h>
|
||||||
|
|
||||||
|
static inline bool equali(NSString *a, NSString *b)
|
||||||
|
{
|
||||||
|
return a && b && [a caseInsensitiveCompare:b] == NSOrderedSame;
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface OBSSparkleUpdateDelegate :
|
||||||
|
NSObject<SUUpdaterDelegate, SUVersionComparison>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@property (nonatomic) bool updateToUndeployed;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation OBSSparkleUpdateDelegate
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize updateToUndeployed;
|
||||||
|
|
||||||
|
- (SUAppcastItem *)bestValidUpdateInAppcast:(SUAppcast *)appcast
|
||||||
|
forUpdater:(SUUpdater *)updater
|
||||||
|
{
|
||||||
|
static SUAppcastItem *selected;
|
||||||
|
SUAppcastItem *item = appcast.items.firstObject;
|
||||||
|
if (!appcast.items.firstObject)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
SUAppcastItem *app = nil, *mpkg = nil;
|
||||||
|
for (SUAppcastItem *item in appcast.items) {
|
||||||
|
NSString *deployed = item.propertiesDictionary[@"ce:deployed"];
|
||||||
|
if (deployed && !(deployed.boolValue || updateToUndeployed))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
NSString *type = item.propertiesDictionary[@"ce:packageType"];
|
||||||
|
if (!mpkg && (!type || equali(type, @"mpkg")))
|
||||||
|
mpkg = item;
|
||||||
|
else if (!app && type && equali(type, @"app"))
|
||||||
|
app = item;
|
||||||
|
|
||||||
|
if (app && mpkg)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app)
|
||||||
|
item = app;
|
||||||
|
|
||||||
|
NSBundle *host = updater.hostBundle;
|
||||||
|
if (mpkg && (!app || equali(host.bundlePath, @"/Applications/OBS.app")))
|
||||||
|
item = mpkg;
|
||||||
|
|
||||||
|
NSMutableDictionary *dict = [NSMutableDictionary
|
||||||
|
dictionaryWithDictionary:item.propertiesDictionary];
|
||||||
|
NSString *build = [host objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||||
|
NSString *url = dict[@"sparkle:releaseNotesLink"];
|
||||||
|
dict[@"sparkle:releaseNotesLink"] = [url stringByAppendingFormat:@"#%@",
|
||||||
|
build];
|
||||||
|
return selected = [[SUAppcastItem alloc] initWithDictionary:dict];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)feedURLStringForUpdater:(SUUpdater *)updater
|
||||||
|
{
|
||||||
|
//URL from Info.plist takes precedence because there may be bundles with
|
||||||
|
//differing feed URLs on the system
|
||||||
|
NSBundle *bundle = updater.hostBundle;
|
||||||
|
return [bundle objectForInfoDictionaryKey:@"SUFeedURL"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareVersion:(NSString *)versionA
|
||||||
|
toVersion:(NSString *)versionB
|
||||||
|
{
|
||||||
|
if (![versionA isEqual:versionB])
|
||||||
|
return NSOrderedAscending;
|
||||||
|
return NSOrderedSame;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id <SUVersionComparison>)
|
||||||
|
versionComparatorForUpdater:(SUUpdater *)__unused updater
|
||||||
|
{
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
static inline bool bundle_matches(NSBundle *bundle)
|
||||||
|
{
|
||||||
|
if (!bundle.executablePath)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NSRange r = [bundle.executablePath rangeOfString:@"Contents/MacOS/"];
|
||||||
|
return [bundle.bundleIdentifier isEqual:@"com.obsproject.obs-studio"] &&
|
||||||
|
r.location != NSNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline NSBundle *find_bundle()
|
||||||
|
{
|
||||||
|
NSFileManager *fm = [NSFileManager defaultManager];
|
||||||
|
NSString *path = [fm currentDirectoryPath];
|
||||||
|
NSString *prev = path;
|
||||||
|
do {
|
||||||
|
NSBundle *bundle = [NSBundle bundleWithPath:path];
|
||||||
|
if (bundle_matches(bundle))
|
||||||
|
return bundle;
|
||||||
|
|
||||||
|
prev = path;
|
||||||
|
path = [path stringByDeletingLastPathComponent];
|
||||||
|
} while (![prev isEqual:path]);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SUUpdater *updater;
|
||||||
|
|
||||||
|
static OBSSparkleUpdateDelegate *delegate;
|
||||||
|
|
||||||
|
void init_sparkle_updater(bool update_to_undeployed)
|
||||||
|
{
|
||||||
|
updater = [SUUpdater updaterForBundle:find_bundle()];
|
||||||
|
delegate = [[OBSSparkleUpdateDelegate alloc] init];
|
||||||
|
delegate.updateToUndeployed = update_to_undeployed;
|
||||||
|
updater.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trigger_sparkle_update()
|
||||||
|
{
|
||||||
|
[updater checkForUpdates:nil];
|
||||||
|
}
|
||||||
|
|
@ -890,8 +890,17 @@ bool OBSBasic::QueryRemoveSource(obs_source_t *source)
|
|||||||
|
|
||||||
#define UPDATE_CHECK_INTERVAL (60*60*24*4) /* 4 days */
|
#define UPDATE_CHECK_INTERVAL (60*60*24*4) /* 4 days */
|
||||||
|
|
||||||
|
#ifdef UPDATE_SPARKLE
|
||||||
|
void init_sparkle_updater(bool update_to_undeployed);
|
||||||
|
void trigger_sparkle_update();
|
||||||
|
#endif
|
||||||
|
|
||||||
void OBSBasic::TimedCheckForUpdates()
|
void OBSBasic::TimedCheckForUpdates()
|
||||||
{
|
{
|
||||||
|
#ifdef UPDATE_SPARKLE
|
||||||
|
init_sparkle_updater(config_get_bool(App()->GlobalConfig(), "General",
|
||||||
|
"UpdateToUndeployed"));
|
||||||
|
#else
|
||||||
long long lastUpdate = config_get_int(App()->GlobalConfig(), "General",
|
long long lastUpdate = config_get_int(App()->GlobalConfig(), "General",
|
||||||
"LastUpdateCheck");
|
"LastUpdateCheck");
|
||||||
uint32_t lastVersion = config_get_int(App()->GlobalConfig(), "General",
|
uint32_t lastVersion = config_get_int(App()->GlobalConfig(), "General",
|
||||||
@ -908,10 +917,14 @@ void OBSBasic::TimedCheckForUpdates()
|
|||||||
|
|
||||||
if (secs > UPDATE_CHECK_INTERVAL)
|
if (secs > UPDATE_CHECK_INTERVAL)
|
||||||
CheckForUpdates();
|
CheckForUpdates();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::CheckForUpdates()
|
void OBSBasic::CheckForUpdates()
|
||||||
{
|
{
|
||||||
|
#ifdef UPDATE_SPARKLE
|
||||||
|
trigger_sparkle_update();
|
||||||
|
#else
|
||||||
ui->actionCheckForUpdates->setEnabled(false);
|
ui->actionCheckForUpdates->setEnabled(false);
|
||||||
|
|
||||||
string versionString("obs-basic ");
|
string versionString("obs-basic ");
|
||||||
@ -926,6 +939,7 @@ void OBSBasic::CheckForUpdates()
|
|||||||
this, SLOT(updateFileFinished()));
|
this, SLOT(updateFileFinished()));
|
||||||
connect(updateReply, SIGNAL(readyRead()),
|
connect(updateReply, SIGNAL(readyRead()),
|
||||||
this, SLOT(updateFileRead()));
|
this, SLOT(updateFileRead()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::updateFileRead()
|
void OBSBasic::updateFileRead()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user