9 Commits
v1.0 ... main

Author SHA1 Message Date
relikd
6e4cc5c7b0 chore: update settings 2023-06-16 20:00:12 +02:00
relikd
bb6289a447 chore: migrate to newer xcode version 2022-09-30 17:54:39 +02:00
relikd
18790b4431 Thumbnail preview 2020-01-17 00:20:52 +01:00
relikd
bf38ca1442 Proper qlmanage debugging + dark mode with media query instead of NSAppearance 2020-01-16 15:47:37 +01:00
relikd
ba4b94278b Update entitlements 2019-08-21 16:38:36 +02:00
relikd
04076facc7 Fix UTI type: org.opml.opml 2019-08-21 16:31:25 +02:00
relikd
0a21931e51 Sandbox & Hardened runtime 2019-08-15 19:57:31 +02:00
relikd
b55807e5db Add dynamic UTI for opml files 2019-08-15 19:56:05 +02:00
relikd
ed0de83487 Shared scheme for upcoming carthage support 2019-08-09 02:02:55 +02:00
11 changed files with 314 additions and 84 deletions

View File

@@ -8,18 +8,26 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
540A649C22EE78B200470937 /* GenerateThumbnailForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */; }; 540A649C22EE78B200470937 /* GenerateThumbnailForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */; };
540A649E22EE78B200470937 /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 540A649D22EE78B200470937 /* GeneratePreviewForURL.m */; }; 540A649E22EE78B200470937 /* GeneratePreviewForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649D22EE78B200470937 /* GeneratePreviewForURL.c */; };
540A64A022EE78B200470937 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649F22EE78B200470937 /* main.c */; }; 540A64A022EE78B200470937 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649F22EE78B200470937 /* main.c */; };
541EF8B322EEFBEA00C415AA /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = 541EF8B122EEFB2300C415AA /* style.css */; }; 541EF8B322EEFBEA00C415AA /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = 541EF8B122EEFB2300C415AA /* style.css */; };
54A75F6023D1269200754813 /* style-thumb.css in Resources */ = {isa = PBXBuildFile; fileRef = 54A75F5F23D1269100754813 /* style-thumb.css */; };
54BFFC1123D09E7300012FBB /* opml-lib.h in Headers */ = {isa = PBXBuildFile; fileRef = 54BFFC0F23D09E7300012FBB /* opml-lib.h */; };
54BFFC1223D09E7300012FBB /* opml-lib.m in Sources */ = {isa = PBXBuildFile; fileRef = 54BFFC1023D09E7300012FBB /* opml-lib.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
540A649822EE78B200470937 /* QLOPML.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QLOPML.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; }; 540A649822EE78B200470937 /* QLOPML.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QLOPML.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; };
540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GenerateThumbnailForURL.c; sourceTree = "<group>"; }; 540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GenerateThumbnailForURL.c; sourceTree = "<group>"; };
540A649D22EE78B200470937 /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneratePreviewForURL.m; sourceTree = "<group>"; }; 540A649D22EE78B200470937 /* GeneratePreviewForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GeneratePreviewForURL.c; sourceTree = "<group>"; };
540A649F22EE78B200470937 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; }; 540A649F22EE78B200470937 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
540A64A122EE78B200470937 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 540A64A122EE78B200470937 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
541EF8B122EEFB2300C415AA /* style.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = style.css; sourceTree = "<group>"; }; 541EF8B122EEFB2300C415AA /* style.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = style.css; sourceTree = "<group>"; };
54A75F5F23D1269100754813 /* style-thumb.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = "style-thumb.css"; sourceTree = "<group>"; };
54BFFC0423D0988A00012FBB /* sample.opml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = sample.opml; sourceTree = SOURCE_ROOT; };
54BFFC0F23D09E7300012FBB /* opml-lib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "opml-lib.h"; sourceTree = "<group>"; };
54BFFC1023D09E7300012FBB /* opml-lib.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "opml-lib.m"; sourceTree = "<group>"; };
54FB05D22305C8F400A088AD /* QLOPML.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLOPML.entitlements; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -52,11 +60,16 @@
540A649A22EE78B200470937 /* QLOPML */ = { 540A649A22EE78B200470937 /* QLOPML */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
54FB05D22305C8F400A088AD /* QLOPML.entitlements */,
54BFFC0F23D09E7300012FBB /* opml-lib.h */,
54BFFC1023D09E7300012FBB /* opml-lib.m */,
540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */, 540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */,
540A649D22EE78B200470937 /* GeneratePreviewForURL.m */, 540A649D22EE78B200470937 /* GeneratePreviewForURL.c */,
540A649F22EE78B200470937 /* main.c */, 540A649F22EE78B200470937 /* main.c */,
540A64A122EE78B200470937 /* Info.plist */, 540A64A122EE78B200470937 /* Info.plist */,
541EF8B122EEFB2300C415AA /* style.css */, 541EF8B122EEFB2300C415AA /* style.css */,
54A75F5F23D1269100754813 /* style-thumb.css */,
54BFFC0423D0988A00012FBB /* sample.opml */,
); );
path = QLOPML; path = QLOPML;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -68,6 +81,7 @@
isa = PBXHeadersBuildPhase; isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
54BFFC1123D09E7300012FBB /* opml-lib.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -98,11 +112,19 @@
540A648F22EE78B200470937 /* Project object */ = { 540A648F22EE78B200470937 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1000; LastUpgradeCheck = 1200;
ORGANIZATIONNAME = relikd; ORGANIZATIONNAME = relikd;
TargetAttributes = { TargetAttributes = {
540A649722EE78B200470937 = { 540A649722EE78B200470937 = {
CreatedOnToolsVersion = 10.0; CreatedOnToolsVersion = 10.0;
SystemCapabilities = {
com.apple.HardenedRuntime = {
enabled = 1;
};
com.apple.Sandbox = {
enabled = 1;
};
};
}; };
}; };
}; };
@@ -112,6 +134,7 @@
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
en, en,
Base,
); );
mainGroup = 540A648E22EE78B200470937; mainGroup = 540A648E22EE78B200470937;
productRefGroup = 540A649922EE78B200470937 /* Products */; productRefGroup = 540A649922EE78B200470937 /* Products */;
@@ -128,6 +151,7 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
54A75F6023D1269200754813 /* style-thumb.css in Resources */,
541EF8B322EEFBEA00C415AA /* style.css in Resources */, 541EF8B322EEFBEA00C415AA /* style.css in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -140,7 +164,8 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
540A649C22EE78B200470937 /* GenerateThumbnailForURL.c in Sources */, 540A649C22EE78B200470937 /* GenerateThumbnailForURL.c in Sources */,
540A649E22EE78B200470937 /* GeneratePreviewForURL.m in Sources */, 54BFFC1223D09E7300012FBB /* opml-lib.m in Sources */,
540A649E22EE78B200470937 /* GeneratePreviewForURL.c in Sources */,
540A64A022EE78B200470937 /* main.c in Sources */, 540A64A022EE78B200470937 /* main.c in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -174,15 +199,17 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_ENTITLEMENTS = QLOPML/QLOPML.entitlements;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -199,12 +226,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES;
}; };
name = Debug; name = Debug;
}; };
@@ -234,15 +260,17 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_ENTITLEMENTS = QLOPML/QLOPML.entitlements;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -253,22 +281,20 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES;
}; };
name = Release; name = Release;
}; };
540A64A522EE78B200470937 /* Debug */ = { 540A64A522EE78B200470937 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_STYLE = Manual; CODE_SIGN_IDENTITY = "Apple Development";
COMBINE_HIDPI_IMAGES = YES; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = UY657LKNHJ;
INFOPLIST_FILE = QLOPML/Info.plist; INFOPLIST_FILE = QLOPML/Info.plist;
INSTALL_PATH = /Library/QuickLook;
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLOPML; PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLOPML;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@@ -279,11 +305,10 @@
540A64A622EE78B200470937 /* Release */ = { 540A64A622EE78B200470937 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_STYLE = Manual; CODE_SIGN_IDENTITY = "Apple Development";
COMBINE_HIDPI_IMAGES = YES; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = UY657LKNHJ;
INFOPLIST_FILE = QLOPML/Info.plist; INFOPLIST_FILE = QLOPML/Info.plist;
INSTALL_PATH = /Library/QuickLook;
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLOPML; PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLOPML;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View File

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "540A649722EE78B200470937"
BuildableName = "QLOPML.qlgenerator"
BlueprintName = "QLOPML"
ReferencedContainer = "container:QLOPML.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<PathRunnable
runnableDebuggingMode = "0"
FilePath = "/usr/bin/qlmanage">
</PathRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "540A649722EE78B200470937"
BuildableName = "QLOPML.qlgenerator"
BlueprintName = "QLOPML"
ReferencedContainer = "container:QLOPML.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
<CommandLineArgument
argument = "-g &apos;${TARGET_BUILD_DIR}/${WRAPPER_NAME}&apos; -c &apos;org.opml.ompl&apos;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "-p &apos;${PROJECT_DIR}/sample.opml&apos;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "-t &apos;${PROJECT_DIR}/sample.opml&apos; -s 512"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "-o &quot;$HOME/Downloads&quot;"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "540A649722EE78B200470937"
BuildableName = "QLOPML.qlgenerator"
BlueprintName = "QLOPML"
ReferencedContainer = "container:QLOPML.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,29 @@
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h>
#include "opml-lib.h"
OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options);
void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview);
/* -----------------------------------------------------------------------------
Generate a preview for file
This function's job is to create preview for designated file
----------------------------------------------------------------------------- */
OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
{
CFBundleRef bundle = QLPreviewRequestGetGeneratorBundle(preview);
CFDataRef data = generateHTML(url, bundle, false);
if (data) {
QLPreviewRequestSetDataRepresentation(preview, data, kUTTypeHTML, NULL);
CFRelease(data);
}
return noErr;
}
void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview)
{
// Implement only if supported
}

View File

@@ -1,6 +1,7 @@
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h> #include <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h> #include <QuickLook/QuickLook.h>
#include "opml-lib.h"
OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize);
void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail); void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail);
@@ -13,10 +14,27 @@ void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbn
OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize)
{ {
// TODO: generate icon with feed count? // test with:
// CGImageRef image = CGImageCreate... // rm -rf ~/Library/QuickLook/QLOPML.qlgenerator && qlmanage -r && rsync -a ~/Library/Developer/Xcode/DerivedData/QLOPML-*/Build/Products/Debug/QLOPML.qlgenerator ~/Library/QuickLook/ && qlmanage -t sample.opml -s 512 -i
// QLThumbnailRequestSetImage(thumbnail, image, NULL); CFBundleRef bundle = QLThumbnailRequestGetGeneratorBundle(thumbnail);
CFDataRef data = generateHTML(url, bundle, true);
if (data) {
QLThumbnailRequestSetThumbnailWithDataRepresentation(thumbnail, data, kUTTypeHTML, NULL, NULL);
CFRelease(data);
}
return noErr; return noErr;
// CGSize thumbSize = CGSizeMake(maxSize.width * (600/800.0), maxSize.height);
// // Draw the webview in the correct context
// CGContextRef context = QLThumbnailRequestCreateContext(thumbnail, thumbSize, false, NULL);
//
// if (context) {
// CFBundleRef bundle = QLThumbnailRequestGetGeneratorBundle(thumbnail);
// renderThumbnail(url, bundle, context, maxSize);
// QLThumbnailRequestFlushContext(thumbnail, context);
// CFRelease(context);
// }
// return noErr;
} }
void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail) void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail)

View File

@@ -11,7 +11,8 @@
<string>QLGenerator</string> <string>QLGenerator</string>
<key>LSItemContentTypes</key> <key>LSItemContentTypes</key>
<array> <array>
<string>org.opml</string> <string>org.opml.opml</string>
<string>dyn.ah62d4rv4ge8086drru</string>
</array> </array>
</dict> </dict>
</array> </array>
@@ -24,7 +25,7 @@
<key>CFBundleName</key> <key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string> <string>$(PRODUCT_NAME)</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>1.3</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>1</string>
<key>CFPlugInDynamicRegisterFunction</key> <key>CFPlugInDynamicRegisterFunction</key>
@@ -48,7 +49,7 @@
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 relikd. Public Domain.</string> <string>Copyright © 2019 relikd. Public Domain.</string>
<key>QLNeedsToBeRunInMainThread</key> <key>QLNeedsToBeRunInMainThread</key>
<false/> <true/>
<key>QLPreviewHeight</key> <key>QLPreviewHeight</key>
<real>600</real> <real>600</real>
<key>QLPreviewWidth</key> <key>QLPreviewWidth</key>
@@ -65,9 +66,9 @@
<string>public.xml</string> <string>public.xml</string>
</array> </array>
<key>UTTypeDescription</key> <key>UTTypeDescription</key>
<string>OPML file</string> <string>OPML document</string>
<key>UTTypeIdentifier</key> <key>UTTypeIdentifier</key>
<string>org.opml</string> <string>org.opml.opml</string>
<key>UTTypeReferenceURL</key> <key>UTTypeReferenceURL</key>
<string>http://dev.opml.org/spec2.html</string> <string>http://dev.opml.org/spec2.html</string>
<key>UTTypeTagSpecification</key> <key>UTTypeTagSpecification</key>
@@ -76,6 +77,12 @@
<array> <array>
<string>opml</string> <string>opml</string>
</array> </array>
<key>public.mime-type</key>
<array>
<string>text/xml</string>
<string>text/x-opml</string>
<string>application/xml</string>
</array>
</dict> </dict>
</dict> </dict>
</array> </array>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>

7
QLOPML/opml-lib.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef opml_lib_h
#define opml_lib_h
CFDataRef generateHTML(CFURLRef url, CFBundleRef bundle, Boolean thumb);
//void renderThumbnail(CFURLRef url, CFBundleRef bundle, CGContextRef context, CGSize maxSize);
#endif /* opml_lib_h */

View File

@@ -1,36 +1,6 @@
#include <CoreFoundation/CoreFoundation.h> #import <Foundation/Foundation.h>
#include <CoreServices/CoreServices.h> #import <AppKit/AppKit.h>
#include <QuickLook/QuickLook.h> //#import <WebKit/WebKit.h>
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
NSData* renderOPML(NSURL* url, CFBundleRef bundle);
OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options);
void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview);
/* -----------------------------------------------------------------------------
Generate a preview for file
This function's job is to create preview for designated file
----------------------------------------------------------------------------- */
OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
{
// qlmanage -r && qlmanage -p test.opml -o tmp/ && edit tmp/test.opml.qlpreview/Preview.html
CFBundleRef bundle = QLPreviewRequestGetGeneratorBundle(preview);
CFDataRef data = CFBridgingRetain(renderOPML((__bridge NSURL*)url, bundle));
if (data) {
QLPreviewRequestSetDataRepresentation(preview, data, kUTTypeHTML, NULL);
}
return noErr;
}
void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview)
{
// Implement only if supported
}
// --------------------------------------------------------------- // ---------------------------------------------------------------
// | // |
@@ -52,13 +22,15 @@ void attribute(NSXMLElement *parent, NSString *key, NSString *value) {
NSXMLElement* section(NSString *title, NSString *container, NSXMLElement *parent) { NSXMLElement* section(NSString *title, NSString *container, NSXMLElement *parent) {
make(@"h3", title, parent); make(@"h3", title, parent);
NSXMLElement *div = make(container, nil, parent); NSXMLElement *div = make(container, nil, parent);
attribute(div, @"class", @"first"); attribute(div, @"class", @"section");
return div; return div;
} }
void appendNode(NSXMLElement *child, NSXMLElement *parent) { void appendNode(NSXMLElement *child, NSXMLElement *parent, Boolean thumb) {
if ([child.name isEqualToString:@"head"]) { if ([child.name isEqualToString:@"head"]) {
if (thumb)
return;
NSXMLElement *dl = section(@"Metadata:", @"dl", parent); NSXMLElement *dl = section(@"Metadata:", @"dl", parent);
for (NSXMLElement *head in child.children) { for (NSXMLElement *head in child.children) {
make(@"dt", head.name, dl); make(@"dt", head.name, dl);
@@ -68,21 +40,23 @@ void appendNode(NSXMLElement *child, NSXMLElement *parent) {
} }
if ([child.name isEqualToString:@"body"]) { if ([child.name isEqualToString:@"body"]) {
parent = section(@"Content:", @"ul", parent); parent = thumb ? make(@"ul", nil, parent) : section(@"Content:", @"ul", parent);
} else if ([child.name isEqualToString:@"outline"]) { } else if ([child.name isEqualToString:@"outline"]) {
if ([child attributeForName:@"separator"].stringValue) { if ([child attributeForName:@"separator"].stringValue) {
make(@"hr", nil, parent); make(@"hr", nil, parent);
} else { } else {
NSString *desc = [child attributeForName:@"title"].stringValue; NSString *desc = [child attributeForName:@"title"].stringValue;
NSString *xmlUrl = [child attributeForName:@"xmlUrl"].stringValue;
if (!desc || desc.length == 0) if (!desc || desc.length == 0)
desc = [child attributeForName:@"text"].stringValue; desc = [child attributeForName:@"text"].stringValue;
// refreshInterval // refreshInterval
NSXMLElement *li = make(@"li", desc, parent); NSXMLElement *li = make(@"li", desc, parent);
if (xmlUrl && xmlUrl.length > 0) { if (!thumb) {
[li addChild:[NSXMLNode textWithStringValue:@" — "]]; NSString *xmlUrl = [child attributeForName:@"xmlUrl"].stringValue;
attribute(make(@"a", xmlUrl, li), @"href", xmlUrl); if (xmlUrl && xmlUrl.length > 0) {
[li addChild:[NSXMLNode textWithStringValue:@" — "]];
attribute(make(@"a", xmlUrl, li), @"href", xmlUrl);
}
} }
} }
if (child.childCount > 0) { if (child.childCount > 0) {
@@ -90,11 +64,11 @@ void appendNode(NSXMLElement *child, NSXMLElement *parent) {
} }
} }
for (NSXMLElement *c in child.children) { for (NSXMLElement *c in child.children) {
appendNode(c, parent); appendNode(c, parent, thumb);
} }
} }
NSData* renderOPML(NSURL* url, CFBundleRef bundle) { NSData* generateHTMLData(NSURL *url, CFBundleRef bundle, Boolean thumb) {
NSError *err; NSError *err;
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfURL:url options:0 error:&err]; NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfURL:url options:0 error:&err];
if (err || !doc) { if (err || !doc) {
@@ -106,22 +80,40 @@ NSData* renderOPML(NSURL* url, CFBundleRef bundle) {
NSXMLElement *head = make(@"head", nil, html); NSXMLElement *head = make(@"head", nil, html);
make(@"title", @"OPML file", head); make(@"title", @"OPML file", head);
CFURLRef path = CFBundleCopyResourceURL(bundle, CFSTR("style"), CFSTR("css"), NULL); CFURLRef path = CFBundleCopyResourceURL(bundle, thumb ? CFSTR("style-thumb") : CFSTR("style"), CFSTR("css"), NULL);
NSString *data = [NSString stringWithContentsOfFile:CFBridgingRelease(path) encoding:NSUTF8StringEncoding error:nil]; NSString *data = [NSString stringWithContentsOfFile:CFBridgingRelease(path) encoding:NSUTF8StringEncoding error:nil];
make(@"style", data, head); make(@"style", data, head);
NSXMLElement *body = make(@"body", nil, html); NSXMLElement *body = make(@"body", nil, html);
NSString *appearance = @"light";
if (@available(macOS 10.14, *)) {
if ([NSAppearance.currentAppearance.name isEqualToString:NSAppearanceNameDarkAqua])
appearance = @"dark";
}
attribute(body, @"class", appearance);
for (NSXMLElement *child in doc.children) { for (NSXMLElement *child in doc.children) {
appendNode(child, body); appendNode(child, body, thumb);
} }
NSXMLDocument *xml = [NSXMLDocument documentWithRootElement:html]; NSXMLDocument *xml = [NSXMLDocument documentWithRootElement:html];
return [xml XMLDataWithOptions:NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement]; return [xml XMLDataWithOptions:NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement];
} }
CFDataRef generateHTML(CFURLRef url, CFBundleRef bundle, Boolean thumb) {
return CFBridgingRetain(generateHTMLData((__bridge NSURL*)url, bundle, thumb));
}
/*void renderThumbnail(CFURLRef url, CFBundleRef bundle, CGContextRef context, CGSize maxSize) {
NSData *data = generateHTMLData((__bridge NSURL*)url, bundle, true);
if (data) {
CGRect rect = CGRectMake(0, 0, 600, 800);
float scale = maxSize.height / rect.size.height;
WebView *webView = [[WebView alloc] initWithFrame:rect];
[webView.mainFrame.frameView scaleUnitSquareToSize:CGSizeMake(scale, scale)];
[webView.mainFrame.frameView setAllowsScrolling:NO];
[webView.mainFrame loadData:data MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:nil];
while ([webView isLoading])
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
[webView display];
NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithGraphicsPort:(void *)context
flipped:webView.isFlipped];
[webView displayRectIgnoringOpacity:webView.bounds inContext:gc];
}
}*/

4
QLOPML/style-thumb.css Normal file
View File

@@ -0,0 +1,4 @@
* { font-family: Courier; }
body { padding: 10px; margin-left: -1.5em; }
ul { padding: 0 0 1em 1.5em; list-style-type: none; }

View File

@@ -1,11 +1,12 @@
* { font-family: Courier; } * { font-family: Courier; }
body { padding: 30px; } body { padding: 30px; background-color: #AAA; color: black; }
dd, li, hr { font-weight: bold; line-height: 1.5em; } dd, li, hr { font-weight: bold; line-height: 1.5em; }
ul { list-style-type: none; padding-bottom: 1em; } ul { list-style-type: none; padding-bottom: 1em; }
a { font-size: 0.75em; color: #FBA43A; } a { font-size: 0.75em; color: #FBA43A; }
.light { background-color: #AAA; color: black; } .section { padding: 1em 1.5em; border-radius: 7px; background-color: #EEE; }
.dark { background-color: #555; color: white; }
.first { padding: 1em 1.5em; border-radius: 7px; } @media (prefers-color-scheme: dark) {
.light .first { background-color: #EEE; } body { background-color: #555; color: white; }
.dark .first { background-color: #222; } .section { background-color: #222; }
}

39
sample.opml Normal file
View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
<head>
<title>Sample OPML file for RSSReader</title>
</head>
<body>
<outline title="News" text="News">
<outline text="Big News Finland" title="Big News Finland" type="rss" xmlUrl="http://www.bignewsnetwork.com/?rss=37e8860164ce009a"/>
<outline text="Euronews" title="Euronews" type="rss" xmlUrl="http://feeds.feedburner.com/euronews/en/news/"/>
<outline text="Reuters Top News" title="Reuters Top News" type="rss" xmlUrl="http://feeds.reuters.com/reuters/topNews"/>
<outline text="Yahoo Europe" title="Yahoo Europe" type="rss" xmlUrl="http://rss.news.yahoo.com/rss/europe"/>
</outline>
<outline title="Leisure" text="Leisure">
<outline text="CNN Entertainment" title="CNN Entertainment" type="rss" xmlUrl="http://rss.cnn.com/rss/edition_entertainment.rss"/>
<outline text="E! News" title="E! News" type="rss" xmlUrl="http://uk.eonline.com/syndication/feeds/rssfeeds/topstories.xml"/>
<outline text="Hollywood Reporter" title="Hollywood Reporter" type="rss" xmlUrl="http://feeds.feedburner.com/thr/news"/>
<outline text="Reuters Entertainment" title="Reuters Entertainment" type="rss" xmlUrl="http://feeds.reuters.com/reuters/entertainment"/>
<outline text="Reuters Music News" title="Reuters Music News" type="rss" xmlUrl="http://feeds.reuters.com/reuters/musicNews"/>
<outline text="Yahoo Entertainment" title="Yahoo Entertainment" type="rss" xmlUrl="http://rss.news.yahoo.com/rss/entertainment"/>
</outline>
<outline title="Sports" text="Sports">
<outline text="Formula 1" title="Formula 1" type="rss" xmlUrl="http://www.formula1.com/rss/news/latest.rss"/>
<outline text="MotoGP" title="MotoGP" type="rss" xmlUrl="http://rss.crash.net/crash_motogp.xml"/>
<outline text="N.Y.Times Track And Field" title="N.Y.Times Track And Field" type="rss" xmlUrl="http://topics.nytimes.com/topics/reference/timestopics/subjects/t/track_and_field/index.html?rss=1"/>
<outline text="Reuters Sports" title="Reuters Sports" type="rss" xmlUrl="http://feeds.reuters.com/reuters/sportsNews"/>
<outline text="Yahoo Sports NHL" title="Yahoo Sports NHL" type="rss" xmlUrl="http://sports.yahoo.com/nhl/rss.xml"/>
<outline text="Yahoo Sports" title="Yahoo Sports" type="rss" xmlUrl="http://rss.news.yahoo.com/rss/sports"/>
</outline>
<outline title="Tech" text="Tech">
<outline text="Coding Horror" title="Coding Horror" type="rss" xmlUrl="http://feeds.feedburner.com/codinghorror/"/>
<outline text="Gadget Lab" title="Gadget Lab" type="rss" xmlUrl="http://www.wired.com/gadgetlab/feed/"/>
<outline text="Gizmodo" title="Gizmodo" type="rss" xmlUrl="http://gizmodo.com/index.xml"/>
<outline text="Reuters Technology" title="Reuters Technology" type="rss" xmlUrl="http://feeds.reuters.com/reuters/technologyNews"/>
</outline>
</body>
</opml>