8 次代码提交
共修改 91 个文件,包含 1640 行新增和 179 行删除

没有与搜索条件相匹配的文件

+2
查看文件
@@ -42,3 +42,5 @@ reference-binaries/
!releases/1.2.0/*.pkg !releases/1.2.0/*.pkg
!releases/1.3.1/*.pkg !releases/1.3.1/*.pkg
!releases/1.3.2/*.pkg
@@ -8,7 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
6945FC8F3088B7220013E108 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC8E3088B7220013E108 /* Cocoa.framework */; }; 6945FC8F3088B7220013E108 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC8E3088B7220013E108 /* Cocoa.framework */; };
6945FC973088B7220013E108 /* beatygril XPC Service.pluginkit in Embed PlugIns */ = {isa = PBXBuildFile; fileRef = 6945FC963088B7220013E108 /* beatygril XPC Service.pluginkit */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6945FC973088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit in Embed PlugIns */ = {isa = PBXBuildFile; fileRef = 6945FC963088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
6945FC9B3088B7220013E108 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9A3088B7220013E108 /* Foundation.framework */; }; 6945FC9B3088B7220013E108 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9A3088B7220013E108 /* Foundation.framework */; };
6945FC9D3088B7220013E108 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9C3088B7220013E108 /* AppKit.framework */; }; 6945FC9D3088B7220013E108 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9C3088B7220013E108 /* AppKit.framework */; };
6945FC9F3088B7220013E108 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9E3088B7220013E108 /* Accelerate.framework */; }; 6945FC9F3088B7220013E108 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9E3088B7220013E108 /* Accelerate.framework */; };
@@ -22,14 +22,14 @@
containerPortal = 6945FC833088B7220013E108 /* Project object */; containerPortal = 6945FC833088B7220013E108 /* Project object */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = 6945FC953088B7220013E108; remoteGlobalIDString = 6945FC953088B7220013E108;
remoteInfo = "XPC Service"; remoteInfo = "FCP-BeautyGirl XPC Service";
}; };
6945FCA43088B7220013E108 /* PBXContainerItemProxy */ = { 6945FCA43088B7220013E108 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 6945FC833088B7220013E108 /* Project object */; containerPortal = 6945FC833088B7220013E108 /* Project object */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = 6945FC953088B7220013E108; remoteGlobalIDString = 6945FC953088B7220013E108;
remoteInfo = "XPC Service"; remoteInfo = "FCP-BeautyGirl XPC Service";
}; };
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
@@ -39,16 +39,16 @@
dstPath = ""; dstPath = "";
dstSubfolder = PlugIns; dstSubfolder = PlugIns;
files = ( files = (
6945FC973088B7220013E108 /* beatygril XPC Service.pluginkit in Embed PlugIns */, 6945FC973088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit in Embed PlugIns */,
); );
name = "Embed PlugIns"; name = "Embed PlugIns";
}; };
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
6945FC8B3088B7220013E108 /* beatygril.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = beatygril.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6945FC8B3088B7220013E108 /* FCP-BeautyGirl.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FCP-BeautyGirl.app; sourceTree = BUILT_PRODUCTS_DIR; };
6945FC8E3088B7220013E108 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 6945FC8E3088B7220013E108 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
6945FC963088B7220013E108 /* beatygril XPC Service.pluginkit */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "beatygril XPC Service.pluginkit"; sourceTree = BUILT_PRODUCTS_DIR; }; 6945FC963088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "FCP-BeautyGirl XPC Service.pluginkit"; sourceTree = BUILT_PRODUCTS_DIR; };
6945FC9A3088B7220013E108 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 6945FC9A3088B7220013E108 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
6945FC9C3088B7220013E108 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 6945FC9C3088B7220013E108 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
6945FC9E3088B7220013E108 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 6945FC9E3088B7220013E108 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
@@ -57,12 +57,12 @@
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
6945FCCB3088B7220013E108 /* Exceptions for "beatygril" folder in "Wrapper Application" target */ = { 6945FCCB3088B7220013E108 /* Exceptions for "FCP-BeautyGirl" folder in "Wrapper Application" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet; isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = ( membershipExceptions = (
"/Localized: Plugin/InfoPlist.strings", "/Localized: Plugin/InfoPlist.strings",
"/Localized: Plugin/Localizable.strings", "/Localized: Plugin/Localizable.strings",
Plugin/beatygrilPlugIn.m, Plugin/FCPBeautyGirlPlugIn.m,
Plugin/Info.plist, Plugin/Info.plist,
Plugin/main.m, Plugin/main.m,
Plugin/PGBeautyRenderer.m, Plugin/PGBeautyRenderer.m,
@@ -74,7 +74,7 @@
); );
target = 6945FC8A3088B7220013E108 /* Wrapper Application */; target = 6945FC8A3088B7220013E108 /* Wrapper Application */;
}; };
6945FCD33088B7220013E108 /* Exceptions for "beatygril" folder in "XPC Service" target */ = { 6945FCD33088B7220013E108 /* Exceptions for "FCP-BeautyGirl" folder in "XPC Service" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet; isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = ( membershipExceptions = (
"/Localized: Wrapper Application/Credits.rtf", "/Localized: Wrapper Application/Credits.rtf",
@@ -91,13 +91,13 @@
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFileSystemSynchronizedRootGroup section */
6945FCA63088B7220013E108 /* beatygril */ = { 6945FCA63088B7220013E108 /* FCP-BeautyGirl */ = {
isa = PBXFileSystemSynchronizedRootGroup; isa = PBXFileSystemSynchronizedRootGroup;
exceptions = ( exceptions = (
6945FCCB3088B7220013E108 /* Exceptions for "beatygril" folder in "Wrapper Application" target */, 6945FCCB3088B7220013E108 /* Exceptions for "FCP-BeautyGirl" folder in "Wrapper Application" target */,
6945FCD33088B7220013E108 /* Exceptions for "beatygril" folder in "XPC Service" target */, 6945FCD33088B7220013E108 /* Exceptions for "FCP-BeautyGirl" folder in "XPC Service" target */,
); );
path = beatygril; path = FCP-BeautyGirl;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
/* End PBXFileSystemSynchronizedRootGroup section */ /* End PBXFileSystemSynchronizedRootGroup section */
@@ -125,7 +125,7 @@
6945FC823088B7220013E108 = { 6945FC823088B7220013E108 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6945FCA63088B7220013E108 /* beatygril */, 6945FCA63088B7220013E108 /* FCP-BeautyGirl */,
6945FC8D3088B7220013E108 /* Frameworks */, 6945FC8D3088B7220013E108 /* Frameworks */,
6945FC8C3088B7220013E108 /* Products */, 6945FC8C3088B7220013E108 /* Products */,
); );
@@ -134,8 +134,8 @@
6945FC8C3088B7220013E108 /* Products */ = { 6945FC8C3088B7220013E108 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6945FC8B3088B7220013E108 /* beatygril.app */, 6945FC8B3088B7220013E108 /* FCP-BeautyGirl.app */,
6945FC963088B7220013E108 /* beatygril XPC Service.pluginkit */, 6945FC963088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -172,11 +172,11 @@
6945FCA53088B7220013E108 /* PBXTargetDependency */, 6945FCA53088B7220013E108 /* PBXTargetDependency */,
); );
fileSystemSynchronizedGroups = ( fileSystemSynchronizedGroups = (
6945FCA63088B7220013E108 /* beatygril */, 6945FCA63088B7220013E108 /* FCP-BeautyGirl */,
); );
name = "Wrapper Application"; name = "FCP-BeautyGirl";
productName = "Wrapper Application"; productName = "FCP-BeautyGirl";
productReference = 6945FC8B3088B7220013E108 /* beatygril.app */; productReference = 6945FC8B3088B7220013E108 /* FCP-BeautyGirl.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
6945FC953088B7220013E108 /* XPC Service */ = { 6945FC953088B7220013E108 /* XPC Service */ = {
@@ -192,11 +192,11 @@
buildRules = ( buildRules = (
); );
fileSystemSynchronizedGroups = ( fileSystemSynchronizedGroups = (
6945FCA63088B7220013E108 /* beatygril */, 6945FCA63088B7220013E108 /* FCP-BeautyGirl */,
); );
name = "XPC Service"; name = "FCP-BeautyGirl XPC Service";
productName = "XPC Service"; productName = "FCP-BeautyGirl XPC Service";
productReference = 6945FC963088B7220013E108 /* beatygril XPC Service.pluginkit */; productReference = 6945FC963088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit */;
productType = "com.apple.product-type.bundle"; productType = "com.apple.product-type.bundle";
}; };
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
@@ -216,7 +216,7 @@
}; };
}; };
}; };
buildConfigurationList = 6945FC863088B7220013E108 /* Build configuration list for PBXProject "beatygril" */; buildConfigurationList = 6945FC863088B7220013E108 /* Build configuration list for PBXProject "FCP-BeautyGirl" */;
developmentRegion = en; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
@@ -316,15 +316,15 @@
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
INFOPLIST_FILE = beatygril/Plugin/Info.plist; INFOPLIST_FILE = FCP-BeautyGirl/Plugin/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@loader_path/../Frameworks", "@loader_path/../Frameworks",
); );
MACH_O_TYPE = mh_execute; MACH_O_TYPE = mh_execute;
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.beatygril.fxplug; PRODUCT_BUNDLE_IDENTIFIER = com.dayu.fcpbeautygirl.fxplug;
PRODUCT_NAME = "beatygril $(TARGET_NAME)"; PRODUCT_NAME = "FCP-BeautyGirl XPC Service";
SWIFT_OBJC_BRIDGING_HEADER = "beatygril/Plugin/XPC Service-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "FCP-BeautyGirl/Plugin/XPC Service-Bridging-Header.h";
WRAPPER_EXTENSION = pluginkit; WRAPPER_EXTENSION = pluginkit;
}; };
name = Debug; name = Debug;
@@ -339,15 +339,15 @@
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
INFOPLIST_FILE = beatygril/Plugin/Info.plist; INFOPLIST_FILE = FCP-BeautyGirl/Plugin/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@loader_path/../Frameworks", "@loader_path/../Frameworks",
); );
MACH_O_TYPE = mh_execute; MACH_O_TYPE = mh_execute;
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.beatygril.fxplug; PRODUCT_BUNDLE_IDENTIFIER = com.dayu.fcpbeautygirl.fxplug;
PRODUCT_NAME = "beatygril $(TARGET_NAME)"; PRODUCT_NAME = "FCP-BeautyGirl XPC Service";
SWIFT_OBJC_BRIDGING_HEADER = "beatygril/Plugin/XPC Service-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "FCP-BeautyGirl/Plugin/XPC Service-Bridging-Header.h";
WRAPPER_EXTENSION = pluginkit; WRAPPER_EXTENSION = pluginkit;
}; };
name = Release; name = Release;
@@ -355,7 +355,7 @@
6945FCD13088B7220013E108 /* Debug configuration for PBXNativeTarget "Wrapper Application" */ = { 6945FCD13088B7220013E108 /* Debug configuration for PBXNativeTarget "Wrapper Application" */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_ENTITLEMENTS = "beatygril/Wrapper Application/SandboxEntitlements.entitlements"; CODE_SIGN_ENTITLEMENTS = "FCP-BeautyGirl/Wrapper Application/SandboxEntitlements.entitlements";
OTHER_LDFLAGS = ("$(inherited)", "-framework", CoreServices, ); OTHER_LDFLAGS = ("$(inherited)", "-framework", CoreServices, );
CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO; CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
@@ -363,17 +363,17 @@
DEVELOPMENT_TEAM = B3W25FX5H5; DEVELOPMENT_TEAM = B3W25FX5H5;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
INFOPLIST_FILE = "beatygril/Wrapper Application/Info.plist"; INFOPLIST_FILE = "FCP-BeautyGirl/Wrapper Application/Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.beatygril; PRODUCT_BUNDLE_IDENTIFIER = com.dayu.fcpbeautygirl;
PRODUCT_NAME = beatygril; PRODUCT_NAME = FCP-BeautyGirl;
SWIFT_OBJC_BRIDGING_HEADER = "beatygril/Wrapper Application/Wrapper Application-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "FCP-BeautyGirl/Wrapper Application/Wrapper Application-Bridging-Header.h";
}; };
name = Debug; name = Debug;
}; };
6945FCD23088B7220013E108 /* Release configuration for PBXNativeTarget "Wrapper Application" */ = { 6945FCD23088B7220013E108 /* Release configuration for PBXNativeTarget "Wrapper Application" */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_ENTITLEMENTS = "beatygril/Wrapper Application/SandboxEntitlements.entitlements"; CODE_SIGN_ENTITLEMENTS = "FCP-BeautyGirl/Wrapper Application/SandboxEntitlements.entitlements";
OTHER_LDFLAGS = ("$(inherited)", "-framework", CoreServices, ); OTHER_LDFLAGS = ("$(inherited)", "-framework", CoreServices, );
CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO; CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
@@ -381,14 +381,14 @@
DEVELOPMENT_TEAM = B3W25FX5H5; DEVELOPMENT_TEAM = B3W25FX5H5;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
INFOPLIST_FILE = "beatygril/Wrapper Application/Info.plist"; INFOPLIST_FILE = "FCP-BeautyGirl/Wrapper Application/Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.beatygril; PRODUCT_BUNDLE_IDENTIFIER = com.dayu.fcpbeautygirl;
PRODUCT_NAME = beatygril; PRODUCT_NAME = FCP-BeautyGirl;
SWIFT_OBJC_BRIDGING_HEADER = "beatygril/Wrapper Application/Wrapper Application-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "FCP-BeautyGirl/Wrapper Application/Wrapper Application-Bridging-Header.h";
}; };
name = Release; name = Release;
}; };
6945FCD43088B7220013E108 /* Debug configuration for PBXProject "beatygril" */ = { 6945FCD43088B7220013E108 /* Debug configuration for PBXProject "FCP-BeautyGirl" */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ADDITIONAL_SDKS = /Library/Developer/SDKs/FxPlug.sdk; ADDITIONAL_SDKS = /Library/Developer/SDKs/FxPlug.sdk;
@@ -461,7 +461,7 @@
}; };
name = Debug; name = Debug;
}; };
6945FCD53088B7220013E108 /* Release configuration for PBXProject "beatygril" */ = { 6945FCD53088B7220013E108 /* Release configuration for PBXProject "FCP-BeautyGirl" */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ADDITIONAL_SDKS = /Library/Developer/SDKs/FxPlug.sdk; ADDITIONAL_SDKS = /Library/Developer/SDKs/FxPlug.sdk;
@@ -531,11 +531,11 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
6945FC863088B7220013E108 /* Build configuration list for PBXProject "beatygril" */ = { 6945FC863088B7220013E108 /* Build configuration list for PBXProject "FCP-BeautyGirl" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
6945FCD43088B7220013E108 /* Debug configuration for PBXProject "beatygril" */, 6945FCD43088B7220013E108 /* Debug configuration for PBXProject "FCP-BeautyGirl" */,
6945FCD53088B7220013E108 /* Release configuration for PBXProject "beatygril" */, 6945FCD53088B7220013E108 /* Release configuration for PBXProject "FCP-BeautyGirl" */,
); );
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
@@ -2,7 +2,7 @@
#import <FxPlug/FxPlugSDK.h> #import <FxPlug/FxPlugSDK.h>
#import "PGBeautyTypes.h" #import "PGBeautyTypes.h"
@interface beatygrilPlugIn : NSObject <FxTileableEffect, FxAnalyzer, FxCustomParameterViewHost_v2> @interface FCPBeautyGirlPlugIn : NSObject <FxTileableEffect, FxAnalyzer, FxCustomParameterViewHost_v2>
@property (nonatomic, assign) id<PROAPIAccessing> apiManager; @property (nonatomic, assign) id<PROAPIAccessing> apiManager;
- (PGBeautySettings)settingsAtTime:(CMTime)time; - (PGBeautySettings)settingsAtTime:(CMTime)time;
- (void)analyzeForward; - (void)analyzeForward;
@@ -1,4 +1,4 @@
#import "beatygrilPlugIn.h" #import "FCPBeautyGirlPlugIn.h"
#import "PGParameterIDs.h" #import "PGParameterIDs.h"
#import "PGBeautyRenderer.h" #import "PGBeautyRenderer.h"
#import "PGFaceProcessor.h" #import "PGFaceProcessor.h"
@@ -12,7 +12,7 @@
static os_log_t PGRenderLog(void) { static os_log_t PGRenderLog(void) {
static os_log_t log; static dispatch_once_t once; static os_log_t log; static dispatch_once_t once;
dispatch_once(&once, ^{ log=os_log_create("com.dayu.beatygril", "render"); }); dispatch_once(&once, ^{ log=os_log_create("com.dayu.fcpbeautygirl", "render"); });
return log; return log;
} }
@@ -84,7 +84,7 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
return [image imageByApplyingTransform:CGAffineTransformMakeTranslation(b.left,b.bottom)]; return [image imageByApplyingTransform:CGAffineTransformMakeTranslation(b.left,b.bottom)];
} }
@interface beatygrilPlugIn () @interface FCPBeautyGirlPlugIn ()
@property (strong) PGBeautyRenderer *beautyRenderer; @property (strong) PGBeautyRenderer *beautyRenderer;
@property (strong) PGFaceProcessor *faceProcessor; @property (strong) PGFaceProcessor *faceProcessor;
@property (strong) PGFaceProcessor *analysisFaceProcessor; @property (strong) PGFaceProcessor *analysisFaceProcessor;
@@ -99,7 +99,7 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
@property (strong) NSHashTable<PGInspectorView *> *inspectorViews; @property (strong) NSHashTable<PGInspectorView *> *inspectorViews;
@end @end
@implementation beatygrilPlugIn @implementation FCPBeautyGirlPlugIn
- (instancetype)initWithAPIManager:(id<PROAPIAccessing>)manager { - (instancetype)initWithAPIManager:(id<PROAPIAccessing>)manager {
if ((self=[super init])) { if ((self=[super init])) {
_apiManager=manager; _apiManager=manager;
@@ -17,9 +17,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>XPC!</string> <string>XPC!</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.3.1</string> <string>1.3.2</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>16</string> <string>17</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string></string> <string></string>
<key>PlugInKit</key> <key>PlugInKit</key>
@@ -57,7 +57,7 @@
<array> <array>
<dict> <dict>
<key>className</key> <key>className</key>
<string>beatygrilPlugIn</string> <string>FCPBeautyGirlPlugIn</string>
<key>displayName</key> <key>displayName</key>
<string>大鱼人像美化</string> <string>大鱼人像美化</string>
<key>group</key> <key>group</key>
@@ -72,7 +72,7 @@
<key>uuid</key> <key>uuid</key>
<string>FB14B0E6-59B2-4836-916F-CD0C559E9241</string> <string>FB14B0E6-59B2-4836-916F-CD0C559E9241</string>
<key>version</key> <key>version</key>
<string>1.3.1</string> <string>1.3.2</string>
</dict> </dict>
<dict> <dict>
<key>className</key> <key>className</key>
@@ -84,7 +84,7 @@
<key>uuid</key> <key>uuid</key>
<string>E0E432C8-3D71-4ABA-B006-E7F519E06C87</string> <string>E0E432C8-3D71-4ABA-B006-E7F519E06C87</string>
<key>version</key> <key>version</key>
<string>1.3.1</string> <string>1.3.2</string>
<key>protocolNames</key> <key>protocolNames</key>
<array> <array>
<string>FxOnScreenControl</string> <string>FxOnScreenControl</string>
@@ -5,7 +5,7 @@
#include <math.h> #include <math.h>
#include <float.h> #include <float.h>
static NSString * const PGFaceErrorDomain = @"media.dayu.PaintFCP.Face"; static NSString * const PGFaceErrorDomain = @"com.dayu.fcpbeautygirl.face";
// Contour origin / internal anchor, in the reference's recovered pin order. // Contour origin / internal anchor, in the reference's recovered pin order.
// The unused middle entry of each reference triplet is intentionally omitted. // The unused middle entry of each reference triplet is intentionally omitted.
static const uint8_t PGThinPins[17][2] = { static const uint8_t PGThinPins[17][2] = {
@@ -0,0 +1 @@
"FCP-BeautyGirl::FxPlug Name" = "大鱼人像美化";
@@ -0,0 +1 @@
"FCP-BeautyGirl::FxPlug Description" = "Portrait smoothing, skin tone, face shaping and automatic face tracking.";
文件已重命名,内容未更改。
@@ -1,6 +1,6 @@
// //
// AppDelegate.h // AppDelegate.h
// beatygril // FCP-BeautyGirl
// //
// Created by dayu on 2026/10/21. // Created by dayu on 2026/10/21.
// //
@@ -8,7 +8,7 @@
@implementation AppDelegate @implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification { - (void)applicationDidFinishLaunching:(NSNotification *)notification {
self.window.title = @"大鱼人像美化 · 免费开源"; self.window.title = @"FCP-BeautyGirl · 大鱼人像美化";
[self.window setContentSize:NSMakeSize(800, 450)]; [self.window setContentSize:NSMakeSize(800, 450)];
self.window.styleMask &= ~NSWindowStyleMaskResizable; self.window.styleMask &= ~NSWindowStyleMaskResizable;
self.window.backgroundColor = [NSColor colorWithRed:0.94 green:0.92 blue:0.85 alpha:1]; self.window.backgroundColor = [NSColor colorWithRed:0.94 green:0.92 blue:0.85 alpha:1];
@@ -20,11 +20,11 @@
<customObject id="YLy-65-1bz" customClass="NSFontManager"/> <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items> <items>
<menuItem title="beatygril" id="1Xt-HY-uBw"> <menuItem title="FCP-BeautyGirl" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="beatygril" systemMenu="apple" id="uQy-DD-JDr"> <menu key="submenu" title="FCP-BeautyGirl" systemMenu="apple" id="uQy-DD-JDr">
<items> <items>
<menuItem title="About beatygril" id="5kV-Vb-QxS"> <menuItem title="About FCP-BeautyGirl" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/> <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
@@ -38,7 +38,7 @@
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/> <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/> <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide beatygril" keyEquivalent="h" id="Olw-nP-bQN"> <menuItem title="Hide FCP-BeautyGirl" keyEquivalent="h" id="Olw-nP-bQN">
<connections> <connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/> <action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections> </connections>
@@ -56,7 +56,7 @@
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/> <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit beatygril" keyEquivalent="q" id="4sb-4s-VLi"> <menuItem title="Quit FCP-BeautyGirl" keyEquivalent="q" id="4sb-4s-VLi">
<connections> <connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/> <action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections> </connections>
@@ -669,7 +669,7 @@
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ"> <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items> <items>
<menuItem title="beatygril Help" keyEquivalent="?" id="FKE-Sm-Kum"> <menuItem title="FCP-BeautyGirl Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections> <connections>
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/> <action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
</connections> </connections>
@@ -679,7 +679,7 @@
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
<window title="beatygril" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g"> <window title="FCP-BeautyGirl" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/> <rect key="contentRect" x="335" y="390" width="480" height="360"/>
@@ -4,6 +4,8 @@
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>FCP-BeautyGirl · 大鱼人像美化</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
@@ -17,9 +19,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.3.1</string> <string>1.3.2</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>16</string> <string>17</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string> <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
+11 -7
查看文件
@@ -1,4 +1,4 @@
# 大鱼人像美化 · beatygril # 大鱼人像美化 · FCP-BeautyGirl
基于本仓库的 FxPlug4 初始工程制作的人像美化滤镜,支持 Motion 和 Final Cut Pro。源码使用 Objective-C、Vision、Core Image 与 Metal。 基于本仓库的 FxPlug4 初始工程制作的人像美化滤镜,支持 Motion 和 Final Cut Pro。源码使用 Objective-C、Vision、Core Image 与 Metal。
@@ -6,28 +6,32 @@
功能包括磨皮、肤色、细节、牙齿美白、眼睛提亮、九类脸型调整、自动人脸跟随和多人处理。原版 MSE18V2 的静态分析依据、近似实现与尚未对齐的部分见 [分析说明](docs/analysis/REA-分析与复刻说明.md)。本版尚未完成原版逐像素与复杂运动跟踪对照。 功能包括磨皮、肤色、细节、牙齿美白、眼睛提亮、九类脸型调整、自动人脸跟随和多人处理。原版 MSE18V2 的静态分析依据、近似实现与尚未对齐的部分见 [分析说明](docs/analysis/REA-分析与复刻说明.md)。本版尚未完成原版逐像素与复杂运动跟踪对照。
1.3.2(17)已统一工程、APP、插件类名和应用ID,正式安装为 `FCP-BeautyGirl.app` / `com.dayu.fcpbeautygirl`,嵌套插件ID为 `com.dayu.fcpbeautygirl.fxplug`。旧APP已迁移清理,滤镜UUID、参数编号和归档格式保持兼容。1901项自动回归及身份迁移检查通过;APP和含配套模板的PKG均已签名、公证、粘附票据和验证。更名后的旧工程重开仍由用户实测。
## 使用 ## 使用
正式安装路径为 `/Library/Plug-Ins/FxPlug/beatygril.app`。Motion 滤镜分类为「大鱼」,滤镜名「大鱼人像美化」。Final Cut Pro 在「效果 → 大鱼磨皮瘦脸 → 大鱼人像美化」中使用配套 Motion 效果,模板目录必须同时保留 `.moef` 与 `Drop Zone.tiff`。美化会随当前帧的人脸自动更新,不需要点击分析。界面以磨皮、美白、瘦脸三张卡片呈现,默认跟随主要人脸;多人模式对多脸变形。单项眼睛可暂时停用并保留数值,右侧箭头恢复默认;磨皮半径、饱和度、锐化和整体混合等收在「更多设置」。旧手动分析与调试参数仅保留隐藏兼容,实际输出统一使用实时自动跟随。 正式安装路径为 `/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app`。Motion 滤镜分类为「大鱼」,滤镜名「大鱼人像美化」。Final Cut Pro 在「效果 → 大鱼磨皮瘦脸 → 大鱼人像美化」中使用配套 Motion 效果,模板目录必须同时保留 `.moef` 与 `Drop Zone.tiff`。美化会随当前帧的人脸自动更新,不需要点击分析。界面以磨皮、美白、瘦脸三张卡片呈现,默认跟随主要人脸;多人模式对多脸变形。单项眼睛可暂时停用并保留数值,右侧箭头恢复默认;磨皮半径、饱和度、锐化和整体混合等收在「更多设置」。旧手动分析与调试参数仅保留隐藏兼容,实际输出统一使用实时自动跟随。
1.3.0 的磨皮卡片依次提供「磨皮程度、微细锐化、五官保护、非肤色区保护」。两种保护默认 100%;降低五官保护让五官区域参与更多磨皮,降低非肤色区保护则扩大磨皮范围,均不扩大肤色提亮范围。微细锐化在局部支持区域恢复纹理;旧全局磨皮和全局锐化仍保留在更多设置,旧工程的参数与归档继续兼容。迁移证据、实现边界与验证见[新版磨皮参数迁移](docs/analysis/新版磨皮参数迁移.md)。1.3.0 的新增参数已随 1.3.1 一并提供。 1.3.0 的磨皮卡片依次提供「磨皮程度、微细锐化、五官保护、非肤色区保护」。两种保护默认 100%;降低五官保护让五官区域参与更多磨皮,降低非肤色区保护则扩大磨皮范围,均不扩大肤色提亮范围。微细锐化在局部支持区域恢复纹理;旧全局磨皮和全局锐化仍保留在更多设置,旧工程的参数与归档继续兼容。迁移证据、实现边界与验证见[新版磨皮参数迁移](docs/analysis/新版磨皮参数迁移.md)。1.3.0 的新增参数已随 1.3.1 一并提供。
1.3.1(16)修复 V 脸影响眼区的问题,改为四组下颌轮廓到外唇的局部采样,并对齐新目标的 0.065 强度映射。1901 项自动检查通过,APP 与本机 PKG 工坊制作的安装包均已签名、公证和验证。正式 APP 已安装;新效果的原生宿主视觉仍由用户实测。原理与边界见 [V 脸下颌区域修复](docs/analysis/V脸下颌区域修复.md)。 1.3.1(16)修复 V 脸影响眼区的问题,改为四组下颌轮廓到外唇的局部采样,并对齐新目标的 0.065 强度映射。1901 项自动检查通过,APP 与本机 PKG 工坊制作的安装包均已签名、公证和验证。正式 APP 已安装;新效果的原生宿主视觉仍由用户实测。原理与边界见 [V 脸下颌区域修复](docs/analysis/V脸下颌区域修复.md)。
当前 [1.3.2 正式下载](https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.2) 与 [大鱼文章](https://dayu.media/15593/) 是本版发布入口,安装包包含「大鱼磨皮瘦脸」分类的配套效果及资源,源码快照也已同步。
## 开发和恢复 ## 开发和恢复
需要 Xcode 27.1、FxPlug SDK 4.3.4 与 PluginManager 1.7.4;最低运行系统 macOS 13。正式产物为 arm64/x86_64 通用版本。 需要 Xcode 27.1、FxPlug SDK 4.3.4 与 PluginManager 1.7.4;最低运行系统 macOS 13。正式产物为 arm64/x86_64 通用版本。
```sh ```sh
./scripts/test.sh ./scripts/test.sh
PAINTFCP_HOST_ASAN=1 ./scripts/test-host.sh FCP_BEAUTYGIRL_HOST_ASAN=1 ./scripts/test-host.sh
PAINTFCP_OSC_ASAN=1 ./scripts/test-osc.sh FCP_BEAUTYGIRL_OSC_ASAN=1 ./scripts/test-osc.sh
xcodebuild -project beatygril/beatygril.xcodeproj -scheme 'Wrapper Application' -configuration Release -derivedDataPath /tmp/paintfcp-build -destination 'generic/platform=macOS' build xcodebuild -project FCP-BeautyGirl/FCP-BeautyGirl.xcodeproj -scheme 'FCP-BeautyGirl' -configuration Release -derivedDataPath /tmp/fcp-beautygirl-build -destination 'generic/platform=macOS' build
``` ```
工程从 `/Library/Developer/SDKs/FxPlug.sdk` 读取头文件与链接信息,从 `/Library/Developer/Frameworks` 嵌入可运行的 Apple 框架。构建默认使用团队 B3W25FX5H5 的 Developer ID Application 身份;正式交付使用 `python3 scripts/deliver.py` 完成公证、粘附和安装;安装前先关闭 Motion 与 FCP,脚本在检测到宿主仍运行时保留原安装版并停止。原生验收完成后继续脚本的清理阶段,清除临时注册与 APP 副本。 工程从 `/Library/Developer/SDKs/FxPlug.sdk` 读取头文件与链接信息,从 `/Library/Developer/Frameworks` 嵌入可运行的 Apple 框架。构建默认使用团队 B3W25FX5H5 的 Developer ID Application 身份;正式交付使用 `python3 scripts/deliver.py` 完成公证、粘附和安装;安装前先关闭 Motion 与 FCP,脚本在检测到宿主仍运行时保留原安装版并停止。原生验收完成后继续脚本的清理阶段,清除临时注册与 APP 副本。
公开源码:[GitHub · FCP-BeatyGril](https://github.com/FAMEDaYu/FCP-BeatyGril)。大鱼站备份:`https://dayu.media/git/dayu/paintfcp-fxplug.git`。恢复入口见 [RECOVERY.md](RECOVERY.md),当前验证记录见 [验证记录](docs/验证记录.md)。原始模板保存在 `baseline-20261021` 标签。 公开源码:[GitHub · FCP-BeautyGirl](https://github.com/dayumeida/FCP-BeautyGirl)。大鱼站备份:`https://dayu.media/git/dayu/paintfcp-fxplug.git`。恢复入口见 [RECOVERY.md](RECOVERY.md),当前验证记录见 [验证记录](docs/验证记录.md)。原始模板保存在 `baseline-20261021` 标签。
继续开发或移交时先读[项目交接文档](docs/项目交接.md),包含当前发布状态、源码入口、坐标与交互约定、验收边界,以及签名打包和双远端保存流程。 继续开发或移交时先读[项目交接文档](docs/项目交接.md),包含当前发布状态、源码入口、坐标与交互约定、验收边界,以及签名打包和双远端保存流程。
@@ -65,4 +69,4 @@ xcodebuild -project beatygril/beatygril.xcodeproj -scheme 'Wrapper Application'
`large.png`(640×360)和 `small.png`(192×108)与 `.moef` 同目录,安装器安装后重新锁定。手动复制或从 Git 恢复模板时,需对这两个 PNG 重新执行 `chflags uchg`,不能锁定整个模板目录。FCP 当前分类为「大鱼磨皮瘦脸」,Motion 原生滤镜分类仍为「大鱼」。 `large.png`(640×360)和 `small.png`(192×108)与 `.moef` 同目录,安装器安装后重新锁定。手动复制或从 Git 恢复模板时,需对这两个 PNG 重新执行 `chflags uchg`,不能锁定整个模板目录。FCP 当前分类为「大鱼磨皮瘦脸」,Motion 原生滤镜分类仍为「大鱼」。
GitHub 提供公开源码、提交历史和版本标签;[1.2.0 Release](https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0) 提供正式签名公证安装包。大鱼站 Git 备份仍受站点登录与会员网关限制,发布文章另提供公开源码快照;安装包始终免费。 GitHub 提供公开源码、提交历史和版本标签;[1.2.0 Release](https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.2.0) 提供正式签名公证安装包。大鱼站 Git 备份仍受站点登录与会员网关限制,发布文章另提供公开源码快照;安装包始终免费。
+21 -2
查看文件
@@ -1,7 +1,10 @@
# 恢复说明 # 恢复说明
当前产品身份自1.3.2(17)统一为FCP-BeautyGirl:工程 `FCP-BeautyGirl/FCP-BeautyGirl.xcodeproj`、scheme `FCP-BeautyGirl`、APP `/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app`、主ID `com.dayu.fcpbeautygirl`、插件ID `com.dayu.fcpbeautygirl.fxplug`。签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`,APP公证Accepted `559eedf0-048f-4d0e-b013-6a187695f2da`,已安装并迁移清理旧APP;程序与滤镜参数、UUID保持兼容。中央身份定义见product.json,旧名称只用于经过ID、签名团队和滤镜UUID验证的迁移。下文历史版本保留各自当时的名称与路径。
- 大鱼备份远程(origin):`https://dayu.media/git/dayu/paintfcp-fxplug.git` - 大鱼备份远程(origin):`https://dayu.media/git/dayu/paintfcp-fxplug.git`
- GitHub 公开远程(github):`https://github.com/FAMEDaYu/FCP-BeatyGril.git` - GitHub 公开远程(github):`https://github.com/dayumeida/FCP-BeautyGirl.git`
- 本地项目根:`/Users/dayu/Documents/PaintFCP` - 本地项目根:`/Users/dayu/Documents/PaintFCP`
- 工作分支:`main` - 工作分支:`main`
- 修改前版本标签:`baseline-20261021`,完整 SHA:`1746f38398588e2367abb37a5c2b31cb64042429` - 修改前版本标签:`baseline-20261021`,完整 SHA:`1746f38398588e2367abb37a5c2b31cb64042429`
@@ -104,7 +107,7 @@ Motion/FCP原生验收范围及未完成项见`docs/verification/v1.1.2/native-q
## GitHub 公开恢复副本 ## GitHub 公开恢复副本
GitHub 远端 `https://github.com/FAMEDaYu/FCP-BeatyGril.git` 已完成完整历史与七个标签的推送,`origin` 及其 main 上游保持大鱼仓库。独立匿名克隆恢复节点为 `356683b41af702d6c0143ad7fa5f540d752d6e14`,197 文件逐字节核验、strict/full fsck 和全部标签回读通过。后续 main 补充发布说明与验证文档,产品源码保持相同。GitHub Release 的公证安装包已匿名下载核对哈希、签名和票据。详见 `docs/GitHub同步说明.md` 和 `docs/verification/github/`。 GitHub 远端 `https://github.com/dayumeida/FCP-BeautyGirl.git` 已完成完整历史与七个标签的推送,`origin` 及其 main 上游保持大鱼仓库。独立匿名克隆恢复节点为 `356683b41af702d6c0143ad7fa5f540d752d6e14`,197 文件逐字节核验、strict/full fsck 和全部标签回读通过。后续 main 补充发布说明与验证文档,产品源码保持相同。GitHub Release 的公证安装包已匿名下载核对哈希、签名和票据。详见 `docs/GitHub同步说明.md` 和 `docs/verification/github/`。
## 1.3.0 新面板参数恢复 ## 1.3.0 新面板参数恢复
@@ -121,3 +124,19 @@ GitHub 远端 `https://github.com/FAMEDaYu/FCP-BeatyGril.git` 已完成完整历
签名源码完整 SHA 为 `7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f`,APP 1.3.1(16),分支 `codex/v-face-jaw-fix`。origin 与 github 同名分支已推送并回读一致。已从 origin 独立克隆该节点,219个受跟踪文件字节和执行位一致、strict/full fsck及Xcode工程读取通过,无LFS或子模块;见 `docs/verification/v1.3.1/recovery-verification.json`。恢复依赖和签名入口沿用本文现有配置,用户帧和私钥不作为源码依赖保存。 签名源码完整 SHA 为 `7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f`,APP 1.3.1(16),分支 `codex/v-face-jaw-fix`。origin 与 github 同名分支已推送并回读一致。已从 origin 独立克隆该节点,219个受跟踪文件字节和执行位一致、strict/full fsck及Xcode工程读取通过,无LFS或子模块;见 `docs/verification/v1.3.1/recovery-verification.json`。恢复依赖和签名入口沿用本文现有配置,用户帧和私钥不作为源码依赖保存。
V 脸现在为四组下颌到外唇局部 pin,映射为 V×0.065,无新版目标已取消的旧尺寸增益。此前瘦脸/下巴/短脸/下颌骨仍保留旧版本映射,大眼/窄脸/颧骨/小头和整体组合保留近似边界。1901项全套及1561项重叠真实帧几何ASan通过。Apple公证 Accepted `e353b701-2fc2-4fcc-b03e-69af7735400f`、staple/validate通过;已在用户确认退出宿主后完成1.3.1正式安装、身份/票据/注册核验和临时副本清理。后续FCP仍有后台进程,通过正常退出菜单结束后才替换APP。PKG由本机PKG工坊CLI制作,包含用户指定分类4项资源,Installer签名、公证Accepted 78105340-306f-4629-8670-772760d4cb9a、票据、Gatekeeper、载荷及隔离脚本均通过;详见同版本交付回执和验证记录。 V 脸现在为四组下颌到外唇局部 pin,映射为 V×0.065,无新版目标已取消的旧尺寸增益。此前瘦脸/下巴/短脸/下颌骨仍保留旧版本映射,大眼/窄脸/颧骨/小头和整体组合保留近似边界。1901项全套及1561项重叠真实帧几何ASan通过。Apple公证 Accepted `e353b701-2fc2-4fcc-b03e-69af7735400f`、staple/validate通过;已在用户确认退出宿主后完成1.3.1正式安装、身份/票据/注册核验和临时副本清理。后续FCP仍有后台进程,通过正常退出菜单结束后才替换APP。PKG由本机PKG工坊CLI制作,包含用户指定分类4项资源,Installer签名、公证Accepted 78105340-306f-4629-8670-772760d4cb9a、票据、Gatekeeper、载荷及隔离脚本均通过;详见同版本交付回执和验证记录。
1.3.1最终发行标签为 `v1.3.1`,完整SHA `b35b4a5d1ca252d2f83c798613560a768274de3c`。GitHub已匿名独立克隆恢复并比对232个受跟踪文件的字节/执行位、strict/full fsck和恢复PKG签名/票据;产品源码与签名节点7fa3298完全一致。见 `docs/verification/v1.3.1/final-tag-recovery.json`。两个远端main纳入该标签后继续记录交付文档,不移动标签。文章15593和GitHub/大鱼Release已更新,GitHub与文章安装包/源码下载字节均校验,完整入口见 `docs/GitHub同步说明.md`。
GitHub于2026-10-22更正仓库名为 `FCP-BeautyGirl`,远端为 `https://github.com/dayumeida/FCP-BeautyGirl.git`。更名后的恢复检查点 `6a29d52a9ad667665da4acf75017c008fa0a566d` 已通过新地址匿名独立克隆、239个文件字节/执行位和strict/full fsck核验,产品源码与此前正式版相同。Release、附件和原有标签保留,文章及本地远程/仓库目录表均已更新;详见 `docs/verification/github/rename-recovery-20261022.json`。
GitHub用户名现为 `dayumeida`,账号ID117798680保持一致。当前公开远端 `https://github.com/dayumeida/FCP-BeautyGirl.git` 的恢复检查点 `2faf7de77929cf7707645ebb38095b03d5729647` 已通过匿名独立克隆、241文件字节/执行位和strict/full fsck核验,产品源码与账号更名前一致。两个仓库的全部分支/标签及Release附件均保留;当前文章、本地github远端和仓库目录表已同步。回执见 `docs/verification/github/username-recovery-20261022.json`。
## 1.3.2 统一产品身份
发行入口为 `v1.3.2`;正式 APP 源码为 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`。新机器按 `product.json` 的工程、scheme 与路径恢复,运行 `python3 scripts/deliver.py --wait-for-hosts --user-tests`;旧产品先验证 Bundle ID、签名团队和滤镜 UUID,再迁移并支持失败回滚。最终包为 `releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg`,SHA-256 `20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1`,签名、公证 Accepted `4a831775-2317-4372-a4cc-102415657ea3`、票据和 Gatekeeper 均通过。正式 APP 已安装并清理旧身份。1901 项自动回归、8 项 APP 迁移、8 项最终 PKG 身份脚本迁移与模板隔离测试通过;未运行真实 installer,原生旧工程重开仍待用户检查。
源码包须从发行标签导出,排除 PKG 二进制并加入 SOURCE-SNAPSHOT.json。发布与独立克隆恢复回执位于 `docs/verification/v1.3.2/`,不包含用户人脸素材、签名私钥或公证凭据。历史标签和旧版本安装包保留,不覆盖。
@@ -1,3 +0,0 @@
/* Localized versions of Info.plist keys */
"beatygril::FxPlug Name" = "beatygril";
@@ -1,4 +0,0 @@
/* Localized versions of Info.plist keys */
"beatygril::FxPlug Description" = "A helpful description of\nwhat this plugin does.";
+29 -5
查看文件
@@ -1,10 +1,10 @@
# GitHub 同步与恢复 # GitHub 同步与恢复
公开源码:https://github.com/FAMEDaYu/FCP-BeatyGril 公开源码:https://github.com/dayumeida/FCP-BeautyGirl
正式安装包:https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0 正式安装包:https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.2
本地 `github` 远端指向上述 GitHub 仓库,`origin` 继续指向大鱼仓库,`main` 仍跟随 `origin/main`。当前项目的完整提交历史、main 和七个版本标签已推送,两端引用与本地一致;未改写历史或覆盖标签。后续更新需要分别推送到 origin 和 github,不会自动定时同步。 本地 `github` 远端指向上述 GitHub 仓库,`origin` 继续指向大鱼仓库,`main` 仍跟随 `origin/main`。当前项目的完整提交历史、main 和全部现有版本标签已推送,两端引用与本地一致;未改写历史或覆盖标签。后续更新需要分别推送到 origin 和 github,不会自动定时同步。
## 已验证的 GitHub 恢复节点 ## 已验证的 GitHub 恢复节点
@@ -13,11 +13,35 @@
安装包:`Dayu-Portrait-1.2.0.pkg`,5,011,005 bytes,SHA-256 `5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243`。Release 标签 `v1.2.0` 仍指向 `3c7261c3a861b9f4704cfb36055d7b500c239dab`,没有重新编译或改动正式安装包。 安装包:`Dayu-Portrait-1.2.0.pkg`,5,011,005 bytes,SHA-256 `5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243`。Release 标签 `v1.2.0` 仍指向 `3c7261c3a861b9f4704cfb36055d7b500c239dab`,没有重新编译或改动正式安装包。
```sh ```sh
git clone https://github.com/FAMEDaYu/FCP-BeatyGril.git git clone https://github.com/dayumeida/FCP-BeautyGirl.git
cd FCP-BeatyGril cd FCP-BeautyGirl
git switch --detach 356683b41af702d6c0143ad7fa5f540d752d6e14 git switch --detach 356683b41af702d6c0143ad7fa5f540d752d6e14
``` ```
本项目没有 LFS 或子模块。编译仍需自行安装 Xcode 和 Apple FxPlug SDK;签名私钥与公证凭据不在 Git 内。GitHub 公共克隆无需登录;大鱼备份仍受站点登录和会员网关限制。两边都只承诺已经提交、推送并核验的节点。 本项目没有 LFS 或子模块。编译仍需自行安装 Xcode 和 Apple FxPlug SDK;签名私钥与公证凭据不在 Git 内。GitHub 公共克隆无需登录;大鱼备份仍受站点登录和会员网关限制。两边都只承诺已经提交、推送并核验的节点。
源代码编写署名:代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。 源代码编写署名:代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。
## 1.3.1 发行与恢复
main已快进纳入1.3.0磨皮参数和1.3.1的V脸下颌修复;origin和github的main及v1.3.1引用已回读核验。v1.3.1固定完整SHA为 `b35b4a5d1ca252d2f83c798613560a768274de3c`,签名APP源码为 `7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f`。独立匿名GitHub克隆232文件字节与执行位一致、strict/full fsck和恢复PKG签名/票据通过。无LFS或子模块。后续main仅补充发布记录,不改写标签。
GitHub Release已提供 `Dayu-Portrait-1.3.1.pkg`(5,011,286 bytes,SHA256 `a6bb7262c9066e7abca8d1f21eaeaf1ba6a1d0d51b4859d39307aa7d7b0bc927`)和源码ZIP(9,682,532 bytes,SHA256 `7c335f54717a73e710ef484fc9f7b90864211c128a0f217bf170aa092333f228`)。两者匿名重新下载哈希一致,PKG签名和票据通过。源码快照基于上述v1.3.1节点,排除PKG本体而保留全部构建源码、模板、素材与验证文档。
大鱼站同名Release附件上传与名称/大小回读通过,下载入口仍受站点登录保护;未宣称API令牌可直接回读该浏览器附件入口。文章15593已就地更新,主包和源码链接的新文件哈希通过,免费规则、封面、作者、分类及未修改资源字段保持一致。正常URL和新请求的前台版本、安装/使用/故障说明及三项SEO均核验,未登录页面显示免费及登录获取入口;未下测试订单。详见verification/v1.3.1。
## 2026-10-22 仓库名称拼写更正
GitHub仓库从 `FAMEDaYu/FCP-BeatyGril` 更名为 `FAMEDaYu/FCP-BeautyGirl`,仓库ID `1428817365` 保持一致。更名前后全部分支/标签SHA、Release与附件ID/大小一致,未另建仓库或改写历史。本地github远端已改为 `https://github.com/dayumeida/FCP-BeautyGirl.git`,origin和main上游仍为原大鱼仓库。现有发布标签、已公证APP/PKG及源码快照保留原始字节,旧快照里的旧链接由GitHub重定向到新地址;当前文档、文章和Release说明使用新地址。插件APP产品名、Bundle ID和安装路径沿用原配置。更名核验见verification/github/rename-20261022.json。
## 2026-10-22 用户名更改
用户将GitHub登录名从 `FAMEDaYu` 改为 `dayumeida`,账号ID117798680保持不变。两个公开仓库迁移到dayumeida名下:FCP-BeautyGirl(ID1428817365)和FCPX-(ID904215594)。更名前后全部分支/标签SHA及Release/附件ID、名称、大小一致。当前项目github远端为 `https://github.com/dayumeida/FCP-BeautyGirl.git`,origin及main上游保持原大鱼仓库;文章15593、活动文档和Release说明更新为新地址。正式版本标签、公证APP/PKG和源码快照保留原始字节,不为账号更名重新构建。个人主页新地址为 `https://github.com/dayumeida`,旧个人主页不提供重定向;仓库旧地址由GitHub重定向。历史验证回执保留当时用户名。账号更名核验见verification/github/username-20261022.json。
## 1.3.2 产品身份统一
发行标签 `v1.3.2`,正式 APP 签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`。新工程和 APP 名为 FCP-BeautyGirl,应用标识及安装路径见 product.json;旧身份仅保留经过验证的迁移入口。GitHub、大鱼 Release 和文章 15593 使用新名称安装包及源码快照,历史发行资料不改写。当前交付与发布核验保存在 verification/v1.3.2。
@@ -0,0 +1,58 @@
{
"repositoryId": 1428817365,
"oldName": "FAMEDaYu/FCP-BeatyGril",
"newName": "FAMEDaYu/FCP-BeautyGirl",
"url": "https://github.com/FAMEDaYu/FCP-BeautyGirl",
"baselineCommit": "cd2e608ec6bb92bb6bb0923e4fb4b7728404c67a",
"allBranchAndTagRefsUnchanged": true,
"releaseAndAssetIdsUnchanged": true,
"githubRemote": "https://github.com/FAMEDaYu/FCP-BeautyGirl.git",
"sourceProductUnchanged": true,
"date": "2026-10-22",
"links": {
"redirects": [
{
"old": "https://github.com/FAMEDaYu/FCP-BeatyGril",
"new": "https://github.com/FAMEDaYu/FCP-BeautyGirl",
"redirectCode": 301,
"newURLStatus": 200
},
{
"old": "https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.3.1",
"new": "https://github.com/FAMEDaYu/FCP-BeautyGirl/releases/tag/v1.3.1",
"redirectCode": 301,
"newURLStatus": 200
}
],
"articleCanonicalLinksVerified": true
},
"globalRepositoryIndex": {
"remote": "https://dayu.media/git/dayu/codex-global-rules.git",
"baseline": "8d3558429efd22af8bad49c03060da326cb231d3",
"commit": "750b430b75e4ccdf5badae8ee3f88a07144b3a9e",
"trackedFilesCompared": 11,
"independentCloneAndFsck": true,
"changedFile": "REPOSITORIES.md"
},
"githubReleaseNotes": [
{
"id": 420500792,
"tag": "v1.3.1",
"assetsUnchanged": true
}
],
"dayuReleaseNotes": [
{
"id": 136,
"tag": "v1.3.1",
"assetsUnchanged": true
}
],
"article": {
"id": 15593,
"url": "https://dayu.media/15593/",
"change": "GitHub repository name/URL only",
"downloadCoverSeoAndAccessPreserved": true
},
"immutableArtifacts": "Existing version tags, notarized APP/PKG and published source ZIP bytes retained; no rebuild or installer upload."
}
@@ -0,0 +1,12 @@
{
"remote": "https://github.com/FAMEDaYu/FCP-BeautyGirl.git",
"commit": "6a29d52a9ad667665da4acf75017c008fa0a566d",
"anonymousClone": true,
"trackedFilesCompared": 239,
"bytesAndExecutableModesMatched": true,
"gitFsckFullStrict": true,
"productSourceUnchangedFrom": "cd2e608ec6bb92bb6bb0923e4fb4b7728404c67a",
"lfs": false,
"submodules": false,
"temporaryCloneRemoved": true
}
@@ -0,0 +1,79 @@
{
"oldLogin": "FAMEDaYu",
"newLogin": "dayumeida",
"accountId": 117798680,
"profileURL": "https://github.com/dayumeida",
"repositories": [
{
"id": 1428817365,
"oldName": "FAMEDaYu/FCP-BeautyGirl",
"newName": "dayumeida/FCP-BeautyGirl",
"allRefsUnchanged": true,
"releasesAndAssetsUnchanged": true
},
{
"id": 904215594,
"oldName": "FAMEDaYu/FCPX-",
"newName": "dayumeida/FCPX-",
"allRefsUnchanged": true,
"releasesAndAssetsUnchanged": true
}
],
"localGithubRemote": "https://github.com/dayumeida/FCP-BeautyGirl.git",
"date": "2026-10-22",
"links": {
"redirects": [
{
"old": "https://github.com/FAMEDaYu/FCP-BeautyGirl",
"final": "https://github.com/dayumeida/FCP-BeautyGirl",
"status": 200
},
{
"old": "https://github.com/FAMEDaYu/FCP-BeatyGril",
"final": "https://github.com/dayumeida/FCP-BeautyGirl",
"status": 200
},
{
"old": "https://github.com/FAMEDaYu/FCP-BeautyGirl/releases/tag/v1.3.1",
"final": "https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.1",
"status": 200
},
{
"old": "https://github.com/FAMEDaYu/FCPX-",
"final": "https://github.com/dayumeida/FCPX-",
"status": 200
}
],
"newProfileStatus": 200,
"articleLinksVerified": true
},
"globalRepositoryIndex": {
"remote": "https://dayu.media/git/dayu/codex-global-rules.git",
"baseline": "750b430b75e4ccdf5badae8ee3f88a07144b3a9e",
"commit": "dde7e2ee26eae18627eefda9b956a6aca52354ad",
"trackedFilesCompared": 11,
"independentCloneAndFsck": true,
"changedFile": "REPOSITORIES.md"
},
"githubReleaseNotes": [
{
"id": 420500792,
"tag": "v1.3.1",
"assetsUnchanged": true
}
],
"dayuReleaseNotes": [
{
"id": 136,
"tag": "v1.3.1",
"assetsUnchanged": true
}
],
"article": {
"id": 15593,
"url": "https://dayu.media/15593/",
"change": "GitHub owner URL only",
"downloadCoverSeoAndAccessPreserved": true
},
"sourceArtifacts": "No change to product source or APP/PKG/source ZIP bytes. Historical verification evidence retains the prior username."
}
@@ -0,0 +1,12 @@
{
"remote": "https://github.com/dayumeida/FCP-BeautyGirl.git",
"commit": "2faf7de77929cf7707645ebb38095b03d5729647",
"anonymousClone": true,
"trackedFilesCompared": 241,
"bytesAndExecutableModesMatched": true,
"gitFsckFullStrict": true,
"productSourceUnchangedFrom": "e47736222d3cbf5edadab26b2a28c82987327043",
"lfs": false,
"submodules": false,
"temporaryCloneRemoved": true
}
@@ -0,0 +1,17 @@
{
"url": "https://dayu.media/git/dayu/paintfcp-fxplug/releases/tag/v1.3.1",
"tag": "v1.3.1",
"uploadAndMetadataReadbackVerified": true,
"assets": [
{
"name": "Dayu-Portrait-1.3.1-source.zip",
"bytes": 9682532
},
{
"name": "Dayu-Portrait-1.3.1.pkg",
"bytes": 5011286
}
],
"assetByteReadback": "Not verified through the browser download gateway: API token request was redirected to site login. GitHub and article asset bytes were independently verified; installer is also stored in Git and restored from the release tag.",
"anonymousAccess": "Site Git gateway continues to require login/membership."
}
@@ -0,0 +1,13 @@
{
"status": "verified",
"tag": "v1.3.1",
"commit": "b35b4a5d1ca252d2f83c798613560a768274de3c",
"anonymousGitHubClone": true,
"trackedFilesCompared": 232,
"byteAndExecutableModesMatch": true,
"gitFsckFullStrict": true,
"productMatchesSignedSource": "7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f",
"restoredPkgSignatureAndTicketVerified": true,
"lfs": false,
"submodules": false
}
@@ -0,0 +1,19 @@
{
"url": "https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.3.1",
"tag": "v1.3.1",
"assets": [
{
"name": "Dayu-Portrait-1.3.1-source.zip",
"bytes": 9682532,
"sha256": "7c335f54717a73e710ef484fc9f7b90864211c128a0f217bf170aa092333f228",
"anonymousDownloadVerified": true
},
{
"name": "Dayu-Portrait-1.3.1.pkg",
"bytes": 5011286,
"sha256": "a6bb7262c9066e7abca8d1f21eaeaf1ba6a1d0d51b4859d39307aa7d7b0bc927",
"anonymousDownloadVerified": true
}
],
"installerSignatureAndTicketVerified": true
}
@@ -0,0 +1,38 @@
{
"articleId": 15593,
"url": "https://dayu.media/15593/",
"status": "publish",
"version": "1.3.1",
"author": 1,
"categories": [
3
],
"featuredMedia": 15595,
"free": true,
"accessAndCoverPreserved": true,
"packageURL": "https://dayu.media/wp-content/uploads/2026/10/1792659519-b628139c96a5fa6.pkg",
"packageBytesAndHashVerifiedByPublisher": true,
"sourceURL": "https://dayu.media/wp-content/uploads/2026/10/1792659515-d487b0a421aacc6.zip",
"frontends": [
{
"request": "normal URL",
"title": "大鱼人像美化 1.3.1|FCP / Motion 免费开源自动美颜插件",
"description": "大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件,1.3.1 修复 V 脸下颌作用区域,并加入微细锐化、五官保护与非肤色区保护。提供 Apple 签名公证 PKG 安装包和源码,安装自动注册,无需激活码,附安装使用及故障排查说明。",
"keywords": "大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源",
"singleSeoTags": true,
"versionAndInstructionsPresent": true,
"anonymousPrice": "free; theme requires login to get package"
},
{
"request": "fresh query",
"title": "大鱼人像美化 1.3.1|FCP / Motion 免费开源自动美颜插件",
"description": "大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件,1.3.1 修复 V 脸下颌作用区域,并加入微细锐化、五官保护与非肤色区保护。提供 Apple 签名公证 PKG 安装包和源码,安装自动注册,无需激活码,附安装使用及故障排查说明。",
"keywords": "大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源",
"singleSeoTags": true,
"versionAndInstructionsPresent": true,
"anonymousPrice": "free; theme requires login to get package"
}
],
"fcpxAppSync": "disabled as before; not requested",
"nativeVisualQA": "pending_user"
}
@@ -0,0 +1,10 @@
{
"sourceCommit": "b35b4a5d1ca252d2f83c798613560a768274de3c",
"tag": "v1.3.1",
"files": 230,
"bytes": 9682532,
"sha256": "7c335f54717a73e710ef484fc9f7b90864211c128a0f217bf170aa092333f228",
"excludes": [
"releases/**/*.pkg"
]
}
+5
查看文件
@@ -0,0 +1,5 @@
Beauty renderer: 57 checks, 0 failures (Metal).
2026-10-22 18:30:09.786 face-tests[35177:8446323] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
Face processing: 116 checks passed
2026-10-22 18:30:23.734 slim-tests[35267:8446747] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
PASS: 1033 slim alignment checks; maximum UV oracle error 1.09828022e-05
@@ -0,0 +1,50 @@
{
"status": "installed_user_qa_pending",
"bundleIdentifier": "com.dayu.fcpbeautygirl",
"installationPath": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
"options": {
"waitForHosts": true,
"userTests": true
},
"nativeEffectQA": {
"status": "pending_user",
"performedByScript": false
},
"source": {
"commit": "767bba8ac11e9bf9268a1e02d1a06d3c120c46aa",
"trackedWorktreeChanges": []
},
"updatedAt": "2026-10-22T10:38:29.383549+00:00",
"version": "1.3.2",
"build": "17",
"stagingSignature": "Executable=/private/tmp/fcp-beautygirl-release/Build/Products/Release/FCP-BeautyGirl.app/Contents/MacOS/FCP-BeautyGirl\nIdentifier=com.dayu.fcpbeautygirl\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=482 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=28f0e84981124d854690d9be80e8ecb7a855ed02\nCandidateCDHashFull sha256=28f0e84981124d854690d9be80e8ecb7a855ed02e3de84009119fc616e22aecd\nHash choices=sha256\nCMSDigest=28f0e84981124d854690d9be80e8ecb7a855ed02e3de84009119fc616e22aecd\nCMSDigestType=2\nCDHash=28f0e84981124d854690d9be80e8ecb7a855ed02\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 18:38:05\nInfo.plist entries=23\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=184\nTotal signatures=1\nChosen signature=1\n",
"notarization": {
"id": "559eedf0-048f-4d0e-b013-6a187695f2da",
"message": "Processing complete",
"status": "Accepted"
},
"signingVerified": true,
"stapleValidated": true,
"stagingPluginUnregistered": true,
"runningHosts": [],
"installedSignature": "Executable=/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app/Contents/MacOS/FCP-BeautyGirl\nIdentifier=com.dayu.fcpbeautygirl\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=482 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=28f0e84981124d854690d9be80e8ecb7a855ed02\nCandidateCDHashFull sha256=28f0e84981124d854690d9be80e8ecb7a855ed02e3de84009119fc616e22aecd\nHash choices=sha256\nCMSDigest=28f0e84981124d854690d9be80e8ecb7a855ed02e3de84009119fc616e22aecd\nCMSDigestType=2\nCDHash=28f0e84981124d854690d9be80e8ecb7a855ed02\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 18:38:05\nNotarization Ticket=stapled\nInfo.plist entries=23\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=184\nTotal signatures=1\nChosen signature=1\n",
"installedSignatureVerified": true,
"installedStapleValidated": true,
"gatekeeperAccepted": true,
"identityMigration": {
"legacyInstallationsRemoved": [
"/Library/Plug-Ins/FxPlug/beatygril.app"
],
"filterUUIDPreserved": "FB14B0E6-59B2-4836-916F-CD0C559E9241"
},
"pluginDiscovery": {
"bundleIdentifier": "com.dayu.fcpbeautygirl.fxplug",
"formalPath": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app/Contents/PlugIns/FCP-BeautyGirl XPC Service.pluginkit",
"output": " com.dayu.fcpbeautygirl.fxplug(1.1)\t6C990AD2-B58E-4C2F-91A4-927849E7AA10\t2026-10-22 10:38:29 +0000\t/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app/Contents/PlugIns/FCP-BeautyGirl XPC Service.pluginkit\n (1 plug-in)\n"
},
"removedGeneratedPaths": [
"/Users/dayu/Documents/PaintFCP/build/delivery/legacy-beatygril.app",
"/tmp/fcp-beautygirl-release",
"/Users/dayu/Documents/PaintFCP/build/delivery/notarization.zip"
]
}
+37
查看文件
@@ -0,0 +1,37 @@
2026-10-22 18:30:11.816 host-tests[35227:8446515] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
Default IOSurface maximum byte difference: 0
Alternate destination tag maximum byte difference: 0
Anatomy default 0/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
Anatomy default 0/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
Anatomy default 1/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
Anatomy default 1/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
Anatomy big-eye 0/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
Anatomy big-eye 0/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
Anatomy big-eye 1/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
Anatomy big-eye 1/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
Anatomy chin-positive 0/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
Anatomy chin-positive 0/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
Anatomy chin-positive 1/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
Anatomy chin-positive 1/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
Anatomy chin-negative 0/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
Anatomy chin-negative 0/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
Anatomy chin-negative 1/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
Anatomy chin-negative 1/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
Anatomy short-positive 0/0 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
Anatomy short-positive 0/1 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
Anatomy short-positive 1/0 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
Anatomy short-positive 1/1 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
Anatomy short-negative 0/0 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
Anatomy short-negative 0/1 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
Anatomy short-negative 1/0 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
Anatomy short-negative 1/1 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
Anatomy jaw 0/0 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
Anatomy jaw 0/1 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
Anatomy jaw 1/0 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
Anatomy jaw 1/1 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
Anatomy v-face 0/0 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
Anatomy v-face 0/1 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
Anatomy v-face 1/0 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
Anatomy v-face 1/1 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
Legacy fallback upright comparison: max=2 mean=0.0010357
Host adapter: 370 checks, 0 failures
@@ -0,0 +1 @@
Inspector: 227 checks, 0 failures
@@ -0,0 +1,35 @@
{
"status": "verified",
"installedProduct": {
"path": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
"bundleId": "com.dayu.fcpbeautygirl",
"version": "1.3.2"
},
"signatureAllArchitecturesVerified": true,
"scopedInventory": {
"roots": [
"/Applications",
"/Library/Plug-Ins/FxPlug",
"/Users/dayu/Library/Plug-Ins/FxPlug",
"/Users/dayu/Documents/PaintFCP",
"/Users/dayu/Desktop",
"/Users/dayu/Downloads",
"/Users/dayu/Library/Developer/Xcode/DerivedData",
"/tmp/fcp-beautygirl-release",
"/tmp/paintfcp-build-20261021"
],
"products": [
{
"path": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
"bundleId": "com.dayu.fcpbeautygirl",
"version": "1.3.2"
}
],
"errors": [],
"scope": "Listed roots only; not all mounted volumes"
},
"legacyPluginOriginalPathAbsent": true,
"filterUUIDPreserved": "FB14B0E6-59B2-4836-916F-CD0C559E9241",
"templateBytesUnchanged": true,
"nativeOldProjectReopen": "pending_user"
}
@@ -0,0 +1,5 @@
........
----------------------------------------------------------------------
Ran 8 tests in 2.805s
OK
@@ -0,0 +1,5 @@
........
----------------------------------------------------------------------
Ran 8 tests in 0.029s
OK
+21
查看文件
@@ -0,0 +1,21 @@
2026-10-22 18:30:08.818 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
2026-10-22 18:30:08.826 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,180) surface=320x240 origin=0
2026-10-22 18:30:09.311 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.8,0.3) setter=(1152,-432) readback=(0.8,0.3) mode=centered-pixels verified=1
2026-10-22 18:30:09.311 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.7,0.4) objectBounds=(-1920,-1080,3840,2160) canvas=(152,78) surface=320x240 origin=0
2026-10-22 18:30:09.359 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.8,0.3) setter=(0.8,0.3) readback=(0.12345,0.87654) mode=normalized verified=0
2026-10-22 18:30:09.359 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.75,0.25) setter=(0.75,0.25) readback=(0.75,0.25) mode=normalized verified=1
2026-10-22 18:30:09.360 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.75,0.25) objectBounds=(-100,-50,200,100) canvas=(160,60) surface=320x240 origin=0
2026-10-22 18:30:09.409 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.625,0.375) setter=(0.625,0.375) readback=(0.625,0.375) mode=normalized verified=1
2026-10-22 18:30:09.409 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.625,0.375) objectBounds=(-100,-50,200,100) canvas=(240,60) surface=320x240 origin=0
2026-10-22 18:30:09.457 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
2026-10-22 18:30:09.457 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(144,180) surface=320x240 origin=0
2026-10-22 18:30:09.506 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
2026-10-22 18:30:09.506 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0,1) objectBounds=(-100,-50,200,100) canvas=(100,140) surface=320x240 origin=0
2026-10-22 18:30:09.574 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(nan,nan) surface=320x240 origin=0
2026-10-22 18:30:09.628 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
2026-10-22 18:30:09.629 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(inf,nan) surface=320x240 origin=0
2026-10-22 18:30:09.689 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
2026-10-22 18:30:09.690 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,nan) surface=320x240 origin=0
2026-10-22 18:30:09.742 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
2026-10-22 18:30:09.742 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
OSC adapter: 98 checks, 0 failures
@@ -0,0 +1,41 @@
{
"status": "verified",
"version": "1.3.2",
"build": "17",
"package": "releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg",
"bytes": 4889706,
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
"sourceApp": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
"sourceCommit": "767bba8ac11e9bf9268a1e02d1a06d3c120c46aa",
"motionSource": "/Users/dayu/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸",
"motionFiles": [
{
"file": "大鱼人像美化/Drop Zone.tiff",
"sha256": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
"locked": false
},
{
"file": "大鱼人像美化/large.png",
"sha256": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
"locked": true
},
{
"file": "大鱼人像美化/small.png",
"sha256": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5",
"locked": true
},
{
"file": "大鱼人像美化/大鱼人像美化.moef",
"sha256": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
"locked": false
}
],
"packager": "/Applications/PKG工坊.app/Contents/MacOS/PKG工坊",
"productMigration": "PKG Forge base plus identity-checked backup/rollback block; final package freshly signed, notarized and stapled",
"notarization": {
"message": "Processing complete",
"id": "4a831775-2317-4372-a4cc-102415657ea3",
"status": "Accepted"
},
"realInstallerExecuted": false
}
@@ -0,0 +1,3 @@
/Users/dayu/Documents/PaintFCP/releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg: accepted
source=Notarized Developer ID
origin=Developer ID Installer: zhong luo (B3W25FX5H5)
@@ -0,0 +1,5 @@
{
"message": "Processing complete",
"id": "4a831775-2317-4372-a4cc-102415657ea3",
"status": "Accepted"
}
@@ -0,0 +1,22 @@
Package "FCP-BeautyGirl-1.3.2.pkg":
Status: signed by a developer certificate issued by Apple for distribution
Notarization: trusted by the Apple notary service
Signed with a trusted timestamp on: 2026-10-22 10:40:28 +0000
Certificate Chain:
1. Developer ID Installer: zhong luo (B3W25FX5H5)
Expires: 2027-02-01 22:12:15 +0000
SHA256 Fingerprint:
4D AC CD 04 A5 4C 7E F8 13 13 A2 ED D1 C2 C0 D0 29 EF FA BF 7B 53
5A 43 C8 72 4D C4 0A A3 94 34
------------------------------------------------------------------------
2. Developer ID Certification Authority
Expires: 2027-02-01 22:12:15 +0000
SHA256 Fingerprint:
7A FC 9D 01 A6 2F 03 A2 DE 96 37 93 6D 4A FE 68 09 0D 2D E1 8D 03
F2 9C 88 CF B0 B1 BA 63 58 7F
------------------------------------------------------------------------
3. Apple Root CA
Expires: 2035-02-09 21:40:36 +0000
SHA256 Fingerprint:
B0 B1 73 0E CB C7 FF 45 05 14 2C 49 F1 29 5E 6E DA 6B CA ED 7E 2C
68 C5 BE 91 B5 A1 10 01 F0 24
+5
查看文件
@@ -0,0 +1,5 @@
productsign: using timestamp authority for signature
productsign: signing product with identity "Developer ID Installer: zhong luo (B3W25FX5H5)" from keychain /Users/dayu/Library/Keychains/login.keychain-db
productsign: adding certificate "Developer ID Certification Authority"
productsign: adding certificate "Apple Root CA"
productsign: Wrote signed product archive to /Users/dayu/Documents/PaintFCP/releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg
+3
查看文件
@@ -0,0 +1,3 @@
Processing: /Users/dayu/Documents/PaintFCP/releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg
Processing: /Users/dayu/Documents/PaintFCP/releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg
The staple and validate action worked!
@@ -0,0 +1,36 @@
{
"package": "releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg",
"bytes": 4889706,
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
"version": "1.3.2",
"build": "17",
"app_files_compared": 34,
"app_byte_and_symlink_equality": true,
"template_files": {
"大鱼人像美化.moef": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
"Drop Zone.tiff": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
"large.png": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
"small.png": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
},
"locked_relative_paths": [
"大鱼人像美化/large.png",
"大鱼人像美化/small.png"
],
"script_sha256": {
"preinstall": "b0562f7705c84a2f34e31df67a4f0d429e60083bab122dad99f56a4b266c0174",
"postinstall": "d147ccab1c428659fd2b0ed60e77399d1eb5910d1049dcdcbdbfc88fd3824300"
},
"isolated_script_tests": [
"fresh install",
"replace old locked thumbnail",
"partial copy failure restores old bytes and locks"
],
"isolation_changes": [
"Console identity/home redirected to task fixture",
"chown replaced with true",
"FxPlug verification skipped; formal app signature and discovery verified separately"
],
"real_installer_execution": false,
"app_and_template_installed": "APP installed through signed delivery workflow; formal template files matched the specified installed category, not changed by running this PKG",
"fonts": "No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed."
}
@@ -0,0 +1,36 @@
{
"package": "releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg",
"bytes": 4889706,
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
"version": "1.3.2",
"build": "17",
"app_files_compared": 34,
"app_byte_and_symlink_equality": true,
"template_files": {
"大鱼人像美化.moef": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
"Drop Zone.tiff": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
"large.png": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
"small.png": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
},
"locked_relative_paths": [
"大鱼人像美化/large.png",
"大鱼人像美化/small.png"
],
"script_sha256": {
"preinstall": "b0562f7705c84a2f34e31df67a4f0d429e60083bab122dad99f56a4b266c0174",
"postinstall": "d147ccab1c428659fd2b0ed60e77399d1eb5910d1049dcdcbdbfc88fd3824300"
},
"isolated_script_tests": [
"fresh install",
"replace old locked thumbnail",
"partial copy failure restores old bytes and locks"
],
"isolation_changes": [
"Console identity/home redirected to task fixture",
"chown replaced with true",
"FxPlug verification skipped; formal app signature and discovery verified separately"
],
"real_installer_execution": false,
"app_and_template_installed": "APP installed through signed delivery workflow; formal template files matched the specified installed category, not changed by running this PKG",
"fonts": "No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed."
}
@@ -0,0 +1,11 @@
识别到 2 个安装内容:
- FCP-BeautyGirl.app
类型:FxPlug 插件
目录:/Library/Plug-Ins/FxPlug
状态:已签名并公证,保留隔离属性,自动验证并修复注册;失败时打开 APP 所在目录
- 大鱼磨皮瘦脸
类型:FCP 效果
目录:~/Movies/Motion Templates.localized/Effects.localized
状态:非 APP,保留隔离属性
识别完成,未生成安装包。
+27
查看文件
@@ -0,0 +1,27 @@
识别到 2 个安装内容:
- FCP-BeautyGirl.app
类型:FxPlug 插件
目录:/Library/Plug-Ins/FxPlug
状态:已签名并公证,保留隔离属性,自动验证并修复注册;失败时打开 APP 所在目录
- 大鱼磨皮瘦脸
类型:FCP 效果
目录:~/Movies/Motion Templates.localized/Effects.localized
状态:非 APP,保留隔离属性
完成:/Users/dayu/Documents/PaintFCP/build/package-1.3.2/base/FCP-BeautyGirl-1.3.2.pkg
本次唯一标识:com.dayu.fcppackage.b20261022104001942.tt2yn7vc
安装包版本:1.3.2(继承 FCP-BeautyGirl.app)
[正在准备内容]
正在整理 2 个内容项
[正在生成安装包]
正在构建组件包
[正在签名]
正在使用 Developer ID Installer 签名
[正在等待 Apple 公证]
已提交 Apple,公证通常需要几分钟
[正在粘附公证票据]
公证已通过,正在粘附票据
[正在验证结果]
正在检查签名和安装包结构
签名、包结构与公证票据验证通过
@@ -0,0 +1,24 @@
{
"baseline": "d1137edd836cc360c53d21c104a06f2435382441",
"signedSource": "767bba8ac11e9bf9268a1e02d1a06d3c120c46aa",
"renderAndStateFilesCompared": [
"PGFaceSelectOSC.m",
"PGParameterIDs.h",
"PGInspectorState.m",
"PGBeautyTypes.h",
"PGBeautyRenderer.m",
"PGFaceProcessor.h",
"FCPBeautyGirlPlugIn.h",
"PGInspectorView.m",
"main.m",
"PGFaceProcessor.m",
"PGBeautyRenderer.h",
"PGInspectorState.h",
"FCPBeautyGirlPlugIn.m",
"PGInspectorView.h"
],
"normalization": "Only entry class/header names, log subsystem and NSError domain differ; pixel and archived-state logic bytes unchanged.",
"regressionChecks": 1901,
"migrationUnitScenarios": 8,
"installerMigrationScenarios": "7 runtime scenarios passed; final package-block check runs after build."
}
+22 -22
查看文件
@@ -2,7 +2,7 @@
更新时间:2026-10-22,Asia/Shanghai。项目根目录:`/Users/dayu/Documents/PaintFCP`。 更新时间:2026-10-22,Asia/Shanghai。项目根目录:`/Users/dayu/Documents/PaintFCP`。
当前正式 APP 为 **1.3.1(16)**,通用 Release、正式签名、Apple公证、票据、Gatekeeper和正式路径注册均已核验,临时APP副本已清理。1901项自动回归及1561项重叠真实帧几何ASan通过,V脸和新磨皮参数的最终宿主视觉仍由用户实测。签名源码 `7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f`;本次PKG由本机PKG工坊CLI打包,包含用户指定已安装的「大鱼磨皮瘦脸」分类及4项模板资源。文章与双远端发行同步状态见本版本回执。 当前正式 APP 为 **1.3.2(17)**,工程、APP、插件服务及应用标识统一为 FCP-BeautyGirl。通用 Release、正式签名、Apple 公证、票据、Gatekeeper 和正式路径注册均已核验,旧 APP 与临时副本已清理。签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`,发行标签 `v1.3.2`。1901 项自动回归、8 项 APP 身份迁移、8 项最终安装脚本身份迁移及模板隔离测试通过。滤镜 UUID、参数编号和归档保持原格式;新身份下的旧工程重开与最终原生视觉仍由用户实测。安装包基础由本机 PKG 工坊 CLI 生成,加入身份迁移后重新签名公证,包含指定已安装的「大鱼磨皮瘦脸」分类四项资源。文章 15593、GitHub 与大鱼 Release 沿用原入口,发布同步结果见本版回执。
代码由 **OpenAI + Codex 全程编写,站长仅参与调试和测试**。文章和仓库须保留这个表述,不使用“站长原创代码”等说法。免费版本无需账号、激活码或付费授权;“自动注册”指系统插件注册。 代码由 **OpenAI + Codex 全程编写,站长仅参与调试和测试**。文章和仓库须保留这个表述,不使用“站长原创代码”等说法。免费版本无需账号、激活码或付费授权;“自动注册”指系统插件注册。
@@ -16,7 +16,7 @@
| 入口 | 用途 | | 入口 | 用途 |
| --- | --- | | --- | --- |
| [1.3.1 交付回执](verification/v1.3.1/delivery-receipt.json) | 当前安装版、签名源码、公证、清理及原生视觉待测范围 | | [1.3.2 交付回执](verification/v1.3.2/delivery-receipt.json) | 当前安装版、签名源码、公证、清理及原生视觉待测范围 |
| [README](../README.md) | 产品介绍、使用与版本变化 | | [README](../README.md) | 产品介绍、使用与版本变化 |
| [恢复说明](../RECOVERY.md) | 精确源码节点、依赖、远端恢复记录 | | [恢复说明](../RECOVERY.md) | 精确源码节点、依赖、远端恢复记录 |
| [GitHub 同步说明](GitHub同步说明.md) | 两个远端、公开克隆及 Release 验证 | | [GitHub 同步说明](GitHub同步说明.md) | 两个远端、公开克隆及 Release 验证 |
@@ -30,12 +30,12 @@
| 项目 | 当前值 | | 项目 | 当前值 |
| --- | --- | | --- | --- |
| 显示名称 | 大鱼人像美化 | | 显示名称 | 大鱼人像美化 |
| Xcode 产品名 | `beatygril`,保留现有拼写 | | Xcode 产品名 | `FCP-BeautyGirl` |
| APP 版本 | `1.3.1` / `16`,arm64 与 x86_64 通用版本 | | APP 版本 | `1.3.2` / `17`,arm64 与 x86_64 通用版本 |
| 唯一正式 APP | `/Library/Plug-Ins/FxPlug/beatygril.app` | | 唯一正式 APP | `/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app` |
| 主 Bundle ID | `com.dayu.beatygril` | | 主 Bundle ID | `com.dayu.fcpbeautygirl` |
| 嵌套插件 | `Contents/PlugIns/beatygril XPC Service.pluginkit` | | 嵌套插件 | `Contents/PlugIns/FCP-BeautyGirl XPC Service.pluginkit` |
| 插件 Bundle ID | `com.dayu.beatygril.fxplug` | | 插件 Bundle ID | `com.dayu.fcpbeautygirl.fxplug` |
| 滤镜 UUID | `FB14B0E6-59B2-4836-916F-CD0C559E9241` | | 滤镜 UUID | `FB14B0E6-59B2-4836-916F-CD0C559E9241` |
| 自定义面板参数 ID | `210` | | 自定义面板参数 ID | `210` |
| FCP 效果分类 | 大鱼磨皮瘦脸 → 大鱼人像美化 | | FCP 效果分类 | 大鱼磨皮瘦脸 → 大鱼人像美化 |
@@ -54,13 +54,13 @@
## 源码结构 ## 源码结构
Xcode 工程:`beatygril/beatygril.xcodeproj`。外层 scheme 为 `Wrapper Application`,插件 target 为 `XPC Service`。 Xcode 工程:`FCP-BeautyGirl/FCP-BeautyGirl.xcodeproj`。外层 scheme 为 `FCP-BeautyGirl`,插件 target 为 `FCP-BeautyGirl XPC Service`。
下表插件文件均位于 `beatygril/beatygril/Plugin/`。 下表插件文件均位于 `FCP-BeautyGirl/FCP-BeautyGirl/Plugin/`。
| 文件或目录 | 职责与修改入口 | | 文件或目录 | 职责与修改入口 |
| --- | --- | | --- | --- |
| `beatygrilPlugIn.m` | FxPlug 参数、宿主 action、图像适配、渲染状态与整体混合 | | `FCPBeautyGirlPlugIn.m` | FxPlug 参数、宿主 action、图像适配、渲染状态与整体混合 |
| `PGFaceProcessor.m` | Vision 检测、76 点、自动跟随、几何稳定、局部变形和几何蒙版 | | `PGFaceProcessor.m` | Vision 检测、76 点、自动跟随、几何稳定、局部变形和几何蒙版 |
| `PGBeautyRenderer.m` | 磨皮、肤色、细节、牙齿和眼睛等外观处理 | | `PGBeautyRenderer.m` | 磨皮、肤色、细节、牙齿和眼睛等外观处理 |
| `PGInspectorView.m` | AppKit 卡片、滑杆、数值框、开关、重置和连续提交 | | `PGInspectorView.m` | AppKit 卡片、滑杆、数值框、开关、重置和连续提交 |
@@ -120,9 +120,9 @@ Xcode 工程:`beatygril/beatygril.xcodeproj`。外层 scheme 为 `Wrapper Appl
```sh ```sh
./scripts/test.sh ./scripts/test.sh
PAINTFCP_HOST_ASAN=1 ./scripts/test-host.sh FCP_BEAUTYGIRL_HOST_ASAN=1 ./scripts/test-host.sh
PAINTFCP_OSC_ASAN=1 ./scripts/test-osc.sh FCP_BEAUTYGIRL_OSC_ASAN=1 ./scripts/test-osc.sh
PAINTFCP_INSPECTOR_ASAN=1 ./scripts/test-inspector.sh FCP_BEAUTYGIRL_INSPECTOR_ASAN=1 ./scripts/test-inspector.sh
python3 scripts/inspector-template.py audit 'Templates/大鱼人像美化/大鱼人像美化.moef' python3 scripts/inspector-template.py audit 'Templates/大鱼人像美化/大鱼人像美化.moef'
``` ```
@@ -157,7 +157,7 @@ python3 scripts/inspector-template.py audit 'Templates/大鱼人像美化/大鱼
| 资源 | 文件 | | 资源 | 文件 |
| --- | --- | | --- | --- |
| 项目封面 | `Assets/Artwork/portrait-cover.png` | | 项目封面 | `Assets/Artwork/portrait-cover.png` |
| APP 说明图 | `beatygril/beatygril/Wrapper Application/Resources/LauncherInfo.png` | | APP 说明图 | `FCP-BeautyGirl/FCP-BeautyGirl/Wrapper Application/Resources/LauncherInfo.png` |
| 大缩略图 | `Templates/大鱼人像美化/large.png`,640×360 | | 大缩略图 | `Templates/大鱼人像美化/large.png`,640×360 |
| 小缩略图 | `Templates/大鱼人像美化/small.png`,192×108 | | 小缩略图 | `Templates/大鱼人像美化/small.png`,192×108 |
| 生成记录 | `docs/design/artwork-manifest.json`、`artwork-prompt.json` | | 生成记录 | `docs/design/artwork-manifest.json`、`artwork-prompt.json` |
@@ -183,7 +183,7 @@ ls -lO "$HOME/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮
python3 scripts/deliver.py python3 scripts/deliver.py
``` ```
脚本获取 `/Users/dayu/.codex/app-delivery-locks/com.dayu.beatygril.lock`,使用固定暂存 `/tmp/paintfcp-build-20261021`,记录到 `build/delivery/`。它构建通用 Release,由内到外签名 Framework、嵌套插件、外层 APP,验证严格签名,提交公证并要求 `Accepted`,粘附并验证票据,等待宿主退出后替换唯一正式路径,检查 Gatekeeper 与 PluginKit。默认停在 `HOST_VALIDATION_PENDING`,完成实际宿主验收及副本盘点后才回车进入清理。 脚本同时获取新ID与product.json所列旧ID的共享交付锁,主锁为 `/Users/dayu/.codex/app-delivery-locks/com.dayu.fcpbeautygirl.lock`,使用固定暂存 `/tmp/fcp-beautygirl-release`,记录到 `build/delivery/`。它构建通用 Release,由内到外签名 Framework、嵌套插件、外层 APP,验证严格签名,提交公证并要求 `Accepted`,粘附并验证票据,等待宿主退出后替换唯一正式路径,检查 Gatekeeper 与 PluginKit。默认停在 `HOST_VALIDATION_PENDING`,完成实际宿主验收及副本盘点后才回车进入清理。
| 选项 | 用途 | | 选项 | 用途 |
| --- | --- | | --- | --- |
@@ -217,8 +217,8 @@ GitHub Release 下载名为 `Dayu-Portrait-1.2.0.pkg`,字节相同,已匿名
文章及发布入口: 文章及发布入口:
- [公开源码仓库](https://github.com/FAMEDaYu/FCP-BeatyGril) - [公开源码仓库](https://github.com/dayumeida/FCP-BeautyGirl)
- [1.2.0 GitHub Release](https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0) - [1.2.0 GitHub Release](https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.2.0)
- [大鱼站文章 15593](https://dayu.media/15593/) - [大鱼站文章 15593](https://dayu.media/15593/)
- [大鱼 Git 备份](https://dayu.media/git/dayu/paintfcp-fxplug) - [大鱼 Git 备份](https://dayu.media/git/dayu/paintfcp-fxplug)
@@ -233,7 +233,7 @@ GitHub Release 下载名为 `Dayu-Portrait-1.2.0.pkg`,字节相同,已匿名
| 本地远端 | 地址 | 说明 | | 本地远端 | 地址 | 说明 |
| --- | --- | --- | | --- | --- | --- |
| `origin` | `https://dayu.media/git/dayu/paintfcp-fxplug.git` | 保持为原远端及 main 上游;网站 Git 网关仍要求登录和有效会员 | | `origin` | `https://dayu.media/git/dayu/paintfcp-fxplug.git` | 保持为原远端及 main 上游;网站 Git 网关仍要求登录和有效会员 |
| `github` | `https://github.com/FAMEDaYu/FCP-BeatyGril.git` | 公开仓库,匿名克隆可用,完整历史和七个标签已保存 | | `github` | `https://github.com/dayumeida/FCP-BeautyGirl.git` | 公开仓库,匿名克隆可用,完整历史和七个标签已保存 |
本项目没有 LFS 或子模块。不要改写原远端、强推、覆盖现有标签或把双端同步描述成自动定时同步。 本项目没有 LFS 或子模块。不要改写原远端、强推、覆盖现有标签或把双端同步描述成自动定时同步。
@@ -250,8 +250,8 @@ GitHub Release 下载名为 `Dayu-Portrait-1.2.0.pkg`,字节相同,已匿名
恢复正式发行源码可以: 恢复正式发行源码可以:
```sh ```sh
git clone https://github.com/FAMEDaYu/FCP-BeatyGril.git git clone https://github.com/dayumeida/FCP-BeautyGirl.git
cd FCP-BeatyGril cd FCP-BeautyGirl
git switch --detach v1.2.0 git switch --detach v1.2.0
``` ```
@@ -261,7 +261,7 @@ git switch --detach v1.2.0
提交和推送使用 `/Users/dayu/.codex/git-backup-locks/` 中的共享互斥锁。锁名为无凭据、转小写并去尾斜线的完整 HTTPS 仓库地址(保留 `.git`)的 SHA-256 加 `.lock`,`owner.json` 记录 PID、cwd、remote;不清理其他仍在工作的持有者。 提交和推送使用 `/Users/dayu/.codex/git-backup-locks/` 中的共享互斥锁。锁名为无凭据、转小写并去尾斜线的完整 HTTPS 仓库地址(保留 `.git`)的 SHA-256 加 `.lock`,`owner.json` 记录 PID、cwd、remote;不清理其他仍在工作的持有者。
本机 GitHub CLI 为 `/opt/homebrew/bin/gh`,本次已由用户登录 `FAMEDaYu`,HTTPS 凭据在钥匙串中。接手时用 `gh auth status` 确认;连接器曾使用其他只读账号,不能用连接器权限推断 CLI 登录失效,也不打印令牌。大鱼仓库管理使用 `dayu-git` CLI,指南在 `/Users/dayu/Documents/dayu-git/README.md` 与 `API.md`。 本机 GitHub CLI 为 `/opt/homebrew/bin/gh`,账号已更名为 `dayumeida`(账号ID117798680;CLI钥匙串条目可能仍以旧名标识,以 `gh api user --jq .login` 核对当前身份),HTTPS 凭据在钥匙串中。接手时用 `gh auth status` 确认;连接器曾使用其他只读账号,不能用连接器权限推断 CLI 登录失效,也不打印令牌。大鱼仓库管理使用 `dayu-git` CLI,指南在 `/Users/dayu/Documents/dayu-git/README.md` 与 `API.md`。
恢复范围仅覆盖已经提交、推送并核验的节点与实际上传的必要资源。用户素材、忽略的 build、私钥不在此范围。大鱼服务器当前只有手动备份,不能据此承诺本机与服务器同时损坏也可恢复。 恢复范围仅覆盖已经提交、推送并核验的节点与实际上传的必要资源。用户素材、忽略的 build、私钥不在此范围。大鱼服务器当前只有手动备份,不能据此承诺本机与服务器同时损坏也可恢复。
+3
查看文件
@@ -145,3 +145,6 @@ Motion:独立普通视频项目,源PTS0、1920×1080/25fps/10秒,媒体通
移除 V 脸的脸框近似宽带,改为新版目标的四组下颌到外唇 pin,单项映射为 clamp(V,0,1)×0.065,不叠加旧尺寸增益。无合法76点时直通,图像与四张蒙版同场变形。1901项自动检查通过:57 Beauty、116 Face、1033几何、370 Host ASan、98 OSC ASan、227 Inspector ASan。原失败复现、点位/CPU/AIR证据和未对齐范围见 analysis/V脸下颌区域修复.md。另对 NASA 人像和本机用户视频11帧运行1561项几何ASan专项(含重复基础用例,不相加),通过;用户帧和完整点坐标未上传。正式APP已安装,严格签名/双架构、票据、Gatekeeper、PluginKit正式路径及有界副本扫描通过,用户视觉仍待实测。APP公证Accepted e353b701-2fc2-4fcc-b03e-69af7735400f。 移除 V 脸的脸框近似宽带,改为新版目标的四组下颌到外唇 pin,单项映射为 clamp(V,0,1)×0.065,不叠加旧尺寸增益。无合法76点时直通,图像与四张蒙版同场变形。1901项自动检查通过:57 Beauty、116 Face、1033几何、370 Host ASan、98 OSC ASan、227 Inspector ASan。原失败复现、点位/CPU/AIR证据和未对齐范围见 analysis/V脸下颌区域修复.md。另对 NASA 人像和本机用户视频11帧运行1561项几何ASan专项(含重复基础用例,不相加),通过;用户帧和完整点坐标未上传。正式APP已安装,严格签名/双架构、票据、Gatekeeper、PluginKit正式路径及有界副本扫描通过,用户视觉仍待实测。APP公证Accepted e353b701-2fc2-4fcc-b03e-69af7735400f。
PKG由本机PKG工坊CLI从正式APP与用户指定已安装的「大鱼磨皮瘦脸」分类发布副本生成,含1个moef、Drop Zone.tiff和两张锁定缩略图。Installer签名、公证Accepted 78105340-306f-4629-8670-772760d4cb9a、票据、Gatekeeper、包内APP34个文件/链接与正式版一致、4模板资源、隔离新装/更新锁图/失败回滚均通过。本次未运行PKG安装器覆盖模板;正式APP通过交付脚本安装,模板保持原用户副本。PKG 5,011,286 bytes,SHA256 a6bb7262c9066e7abca8d1f21eaeaf1ba6a1d0d51b4859d39307aa7d7b0bc927。 PKG由本机PKG工坊CLI从正式APP与用户指定已安装的「大鱼磨皮瘦脸」分类发布副本生成,含1个moef、Drop Zone.tiff和两张锁定缩略图。Installer签名、公证Accepted 78105340-306f-4629-8670-772760d4cb9a、票据、Gatekeeper、包内APP34个文件/链接与正式版一致、4模板资源、隔离新装/更新锁图/失败回滚均通过。本次未运行PKG安装器覆盖模板;正式APP通过交付脚本安装,模板保持原用户副本。PKG 5,011,286 bytes,SHA256 a6bb7262c9066e7abca8d1f21eaeaf1ba6a1d0d51b4859d39307aa7d7b0bc927。
1.3.1已发布至GitHub和大鱼Release,origin/github的main、修复分支与v1.3.1标签已同步回读。GitHub两个附件匿名下载哈希、安装包签名及票据通过;匿名独立标签克隆232文件、fsck和恢复包验证通过。文章15593就地更新为1.3.1,主下载PKG与源码ZIP的线上字节哈希一致,作者/封面/分类/免费及会员规则保留,前台正常和新请求的版本/说明/SEO通过。未登录前台仍显示免费及登录获取入口,未进行真实测试订单。大鱼Release只完成附件上传元数据回读,API令牌访问浏览器下载入口被重定向登录,未宣称该附件字节回读通过;必要PKG本体已随Git提交并在独立克隆中恢复。
+25
查看文件
@@ -0,0 +1,25 @@
{
"name": "FCP-BeautyGirl",
"version": "1.3.2",
"build": "17",
"bundleIdentifier": "com.dayu.fcpbeautygirl",
"pluginName": "FCP-BeautyGirl XPC Service.pluginkit",
"pluginBundleIdentifier": "com.dayu.fcpbeautygirl.fxplug",
"pluginClass": "FCPBeautyGirlPlugIn",
"sourceRoot": "FCP-BeautyGirl",
"sourceDirectory": "FCP-BeautyGirl/FCP-BeautyGirl",
"xcodeProject": "FCP-BeautyGirl/FCP-BeautyGirl.xcodeproj",
"scheme": "FCP-BeautyGirl",
"installationPath": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
"filterUUID": "FB14B0E6-59B2-4836-916F-CD0C559E9241",
"teamIdentifier": "B3W25FX5H5",
"legacyProducts": [
{
"name": "beatygril",
"bundleIdentifier": "com.dayu.beatygril",
"pluginName": "beatygril XPC Service.pluginkit",
"pluginBundleIdentifier": "com.dayu.beatygril.fxplug",
"installationPath": "/Library/Plug-Ins/FxPlug/beatygril.app"
}
]
}
+2 -2
查看文件
@@ -1,9 +1,9 @@
# 大鱼人像美化 1.2.0(14) # 大鱼人像美化 1.2.0(14)
- 发布文章:https://dayu.media/15593/ - 发布文章:https://dayu.media/15593/
- 公开源码:https://github.com/FAMEDaYu/FCP-BeatyGril - 公开源码:https://github.com/dayumeida/FCP-BeautyGirl
- 大鱼备份:https://dayu.media/git/dayu/paintfcp-fxplug - 大鱼备份:https://dayu.media/git/dayu/paintfcp-fxplug
- GitHub Release:https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0 - GitHub Release:https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.2.0
- 大鱼 Release:https://dayu.media/git/dayu/paintfcp-fxplug/releases/tag/v1.2.0 - 大鱼 Release:https://dayu.media/git/dayu/paintfcp-fxplug/releases/tag/v1.2.0
- 标签完整 SHA:3c7261c3a861b9f4704cfb36055d7b500c239dab - 标签完整 SHA:3c7261c3a861b9f4704cfb36055d7b500c239dab
- 正式 APP 源码:696d5f39b30404ed5d1d4c25f61d17475c7fc91b - 正式 APP 源码:696d5f39b30404ed5d1d4c25f61d17475c7fc91b
+1 -1
查看文件
@@ -2,7 +2,7 @@
"title": "大鱼人像美化 1.2.0:FCP / Motion 免费开源自动美颜插件", "title": "大鱼人像美化 1.2.0:FCP / Motion 免费开源自动美颜插件",
"slug": "dayu-portrait-beauty", "slug": "dayu-portrait-beauty",
"status": "publish", "status": "publish",
"content": "<!-- wp:paragraph -->\n<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>\n<!-- /wp:paragraph -->\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"{{media.cover.url}}\" alt=\"大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜\"/><figcaption>古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>\n<!-- /wp:image -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">可以做什么</h2>\n<!-- /wp:heading -->\n<!-- wp:list -->\n<ul class=\"wp-block-list\"><li>磨皮:局部磨皮、全局磨皮与五官保护,强度分别控制。</li><li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li><li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li><li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li><li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li></ul>\n<!-- /wp:list -->\n<!-- wp:paragraph -->\n<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">版本与下载</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>当前版本 <strong>1.2.0(14)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>本次更新加入古风封面与锁定缩略图、免费开源说明页和主 APP 三秒自动退出。人脸处理与面板交互沿用 1.1.2 已验收实现,不需要重新运行手动分析。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">安装</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/beatygril.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>\n<!-- /wp:paragraph -->\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png\" alt=\"主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出\"/></figure>\n<!-- /wp:image -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">使用</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">常见问题</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>如果效果没有出现或显示红色警告,先退出 Final Cut Pro 和 Motion,再打开一次主 APP,等待其自动退出,然后重新启动宿主。可在“终端”执行下面这条命令:</p>\n<!-- /wp:paragraph -->\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code>open '/Library/Plug-Ins/FxPlug/beatygril.app'</code></pre>\n<!-- /wp:code -->\n<!-- wp:paragraph -->\n<p>该流程可重新触发系统注册,并不能解决所有报错。仍异常时请核对 macOS、Line truncated "content": "<!-- wp:paragraph -->\n<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>\n<!-- /wp:paragraph -->\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"{{media.cover.url}}\" alt=\"大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜\"/><figcaption>古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>\n<!-- /wp:image -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">可以做什么</h2>\n<!-- /wp:heading -->\n<!-- wp:list -->\n<ul class=\"wp-block-list\"><li>磨皮:局部磨皮、全局磨皮与五官保护,强度分别控制。</li><li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li><li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li><li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li><li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li></ul>\n<!-- /wp:list -->\n<!-- wp:paragraph -->\n<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">版本与下载</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>当前版本 <strong>1.2.0(14)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>本次更新加入古风封面与锁定缩略图、免费开源说明页和主 APP 三秒自动退出。人脸处理与面板交互沿用 1.1.2 已验收实现,不需要重新运行手动分析。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">安装</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/beatygril.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>\n<!-- /wp:paragraph -->\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png\" alt=\"主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出\"/></figure>\n<!-- /wp:image -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">使用</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>\n<!-- /wp:paragraph -->\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">常见问题</h2>\n<!-- /wp:heading -->\n<!-- wp:paragraph -->\n<p>如果效果没有出现或显示红色警告,先退出 Final Cut Pro 和 Motion,再打开一次主 APP,等待其自动退出,然后重新启动宿主。可在“终端”执行下面这条命令:</p>\n<!-- /wp:paragraph -->\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code>open '/Library/Plug-Ins/FxPlug/beatygril.app'</code></pre>\n<!-- /wp:code -->\n<!-- wp:paragraph -->\n<p>该流程可重新触发系统注册,并不能解决所有报错。仍异常时请核对 macOS、Line truncated
"excerpt": "磨皮、美白、瘦脸与自动人脸跟随,原生卡片面板实时预览。免费开源,自动注册,无需激活码;提供签名公证安装包和源码。", "excerpt": "磨皮、美白、瘦脸与自动人脸跟随,原生卡片面板实时预览。免费开源,自动注册,无需激活码;提供签名公证安装包和源码。",
"categories": [ "categories": [
3 3
+1 -1
查看文件
@@ -62,7 +62,7 @@
<h2 class="wp-block-heading">源码与开源许可</h2> <h2 class="wp-block-heading">源码与开源许可</h2>
<!-- /wp:heading --> <!-- /wp:heading -->
<!-- wp:paragraph --> <!-- wp:paragraph -->
<p>公开源码仓库:<a href="https://github.com/FAMEDaYu/FCP-BeatyGril" target="_blank" rel="noreferrer noopener">GitHub · FCP-BeatyGril</a>,可直接浏览源码、完整提交历史和版本标签。<a href="https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0" target="_blank" rel="noreferrer noopener">1.2.0 Release</a> 提供正式签名公证安装包。大鱼站仓库作为备份保留:<a href="https://dayu.media/git/dayu/paintfcp-fxplug" target="_blank" rel="noreferrer noopener">paintfcp-fxplug</a>(该入口仍受站点登录与会员网关限制)。也可下载 <a href="{{source_url}}">1.2.0 源码快照 ZIP</a>,源码与安装包均免费提供。</p> <p>公开源码仓库:<a href="https://github.com/dayumeida/FCP-BeautyGirl" target="_blank" rel="noreferrer noopener">GitHub · FCP-BeautyGirl</a>,可直接浏览源码、完整提交历史和版本标签。<a href="https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.2.0" target="_blank" rel="noreferrer noopener">1.2.0 Release</a> 提供正式签名公证安装包。大鱼站仓库作为备份保留:<a href="https://dayu.media/git/dayu/paintfcp-fxplug" target="_blank" rel="noreferrer noopener">paintfcp-fxplug</a>(该入口仍受站点登录与会员网关限制)。也可下载 <a href="{{source_url}}">1.2.0 源码快照 ZIP</a>,源码与安装包均免费提供。</p>
<!-- /wp:paragraph --> <!-- /wp:paragraph -->
<!-- wp:paragraph --> <!-- wp:paragraph -->
<p>项目代码按仓库中的 MIT 许可文件提供,源码包含 Xcode 工程、Objective-C / Metal 实现、模板及构建与验证说明。Apple SDK、运行框架及样本按各自许可使用,详见源码中的 LICENSE 和 THIRD_PARTY_NOTICES.md。自行编译需要 Xcode 与 FxPlug SDK;证书和签名私钥不包含在源码中。</p> <p>项目代码按仓库中的 MIT 许可文件提供,源码包含 Xcode 工程、Objective-C / Metal 实现、模板及构建与验证说明。Apple SDK、运行框架及样本按各自许可使用,详见源码中的 LICENSE 和 THIRD_PARTY_NOTICES.md。自行编译需要 Xcode 与 FxPlug SDK;证书和签名私钥不包含在源码中。</p>
+1 -1
查看文件
@@ -3,7 +3,7 @@
修复V脸作用区域,改为四组实际下颌轮廓到外唇的局部采样;同时包含1.3.0的微细锐化、连续五官保护与非肤色区保护。1901项自动回归通过,另有1561项重叠真实帧几何ASan检查;新效果在原生宿主中的最终视觉仍待用户结合素材实测。 修复V脸作用区域,改为四组实际下颌轮廓到外唇的局部采样;同时包含1.3.0的微细锐化、连续五官保护与非肤色区保护。1901项自动回归通过,另有1561项重叠真实帧几何ASan检查;新效果在原生宿主中的最终视觉仍待用户结合素材实测。
- 文章:https://dayu.media/15593/ - 文章:https://dayu.media/15593/
- GitHub:https://github.com/FAMEDaYu/FCP-BeatyGril - GitHub:https://github.com/dayumeida/FCP-BeautyGirl
- 大鱼备份:https://dayu.media/git/dayu/paintfcp-fxplug - 大鱼备份:https://dayu.media/git/dayu/paintfcp-fxplug
- 发布标签:v1.3.1 - 发布标签:v1.3.1
- 正式APP源码:7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f - 正式APP源码:7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f
+1 -1
查看文件
@@ -1,7 +1,7 @@
{ {
"title": "大鱼人像美化 1.3.1:FCP / Motion 免费开源自动美颜插件", "title": "大鱼人像美化 1.3.1:FCP / Motion 免费开源自动美颜插件",
"status": "publish", "status": "publish",
"content": "<!-- wp:paragraph -->\n<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604750-357ca780597c39f.png\" alt=\"大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜\" /><figcaption class=\"wp-element-caption\">古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>\n<!-- /wp:image -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">可以做什么</h2>\n<!-- /wp:heading -->\n\n<!-- wp:list {\"className\":\"wp-block-list\"} -->\n<ul class=\"wp-block-list\"><!-- wp:list-item -->\n<li>磨皮:磨皮程度、微细锐化、五官保护和非肤色区保护分别调节;全局磨皮与锐化保留在更多设置。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li>\n<!-- /wp:list-item --></ul>\n<!-- /wp:list -->\n\n<!-- wp:paragraph -->\n<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">版本与下载</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>当前版本 <strong>1.3.1(16)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>1.3.1 修复 V 脸影响眼区的问题,改为沿实际下颌轮廓进行局部调整;同时包含 1.3.0 新增的微细锐化、连续五官保护和非肤色区保护。两项保护默认 100%,支持旧工程参数。1901 项自动检查通过,另有真实帧几何检查;新参数及 V 脸在原生宿主中的最终视觉效果仍需结合素材实测。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">安装</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/beatygril.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png\" alt=\"主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出\" /></figure>\n<!-- /wp:image -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">使用</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>\n<!-- /wpLine truncated "content": "<!-- wp:paragraph -->\n<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604750-357ca780597c39f.png\" alt=\"大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜\" /><figcaption class=\"wp-element-caption\">古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>\n<!-- /wp:image -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">可以做什么</h2>\n<!-- /wp:heading -->\n\n<!-- wp:list {\"className\":\"wp-block-list\"} -->\n<ul class=\"wp-block-list\"><!-- wp:list-item -->\n<li>磨皮:磨皮程度、微细锐化、五官保护和非肤色区保护分别调节;全局磨皮与锐化保留在更多设置。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li>\n<!-- /wp:list-item --></ul>\n<!-- /wp:list -->\n\n<!-- wp:paragraph -->\n<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">版本与下载</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>当前版本 <strong>1.3.1(16)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>1.3.1 修复 V 脸影响眼区的问题,改为沿实际下颌轮廓进行局部调整;同时包含 1.3.0 新增的微细锐化、连续五官保护和非肤色区保护。两项保护默认 100%,支持旧工程参数。1901 项自动检查通过,另有真实帧几何检查;新参数及 V 脸在原生宿主中的最终视觉效果仍需结合素材实测。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">安装</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/beatygril.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png\" alt=\"主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出\" /></figure>\n<!-- /wp:image -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">使用</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>\n<!-- /wpLine truncated
"excerpt": "1.3.1 修复 V 脸下颌作用区域,新增微细锐化、五官保护与非肤色区保护。免费开源,提供签名公证安装包及源码。", "excerpt": "1.3.1 修复 V 脸下颌作用区域,新增微细锐化、五官保护与非肤色区保护。免费开源,提供签名公证安装包及源码。",
"resource": { "resource": {
"cao_status": true, "cao_status": true,
+112
查看文件
@@ -0,0 +1,112 @@
<!-- wp:paragraph -->
<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"full"} -->
<figure class="wp-block-image size-full"><img src="https://dayu.media/wp-content/uploads/2026/10/1792604750-357ca780597c39f.png" alt="大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜" /><figcaption class="wp-element-caption">古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>
<!-- /wp:image -->
<!-- wp:heading -->
<h2 class="wp-block-heading">可以做什么</h2>
<!-- /wp:heading -->
<!-- wp:list {"className":"wp-block-list"} -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>磨皮:磨皮程度、微细锐化、五官保护和非肤色区保护分别调节;全局磨皮与锐化保留在更多设置。</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->
<!-- wp:paragraph -->
<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">版本与下载</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>当前版本 <strong>1.3.1(16)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>1.3.1 修复 V 脸影响眼区的问题,改为沿实际下颌轮廓进行局部调整;同时包含 1.3.0 新增的微细锐化、连续五官保护和非肤色区保护。两项保护默认 100%,支持旧工程参数。1901 项自动检查通过,另有真实帧几何检查;新参数及 V 脸在原生宿主中的最终视觉效果仍需结合素材实测。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">安装</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/beatygril.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"full"} -->
<figure class="wp-block-image size-full"><img src="https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png" alt="主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出" /></figure>
<!-- /wp:image -->
<!-- wp:heading -->
<h2 class="wp-block-heading">使用</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">常见问题</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>如果效果没有出现或显示红色警告,先退出 Final Cut Pro 和 Motion,再打开一次主 APP,等待其自动退出,然后重新启动宿主。可在“终端”执行下面这条命令:</p>
<!-- /wp:paragraph -->
<!-- wp:code -->
<pre class="wp-block-code"><code>open '/Library/Plug-Ins/FxPlug/beatygril.app'</code></pre>
<!-- /wp:code -->
<!-- wp:paragraph -->
<p>该流程可重新触发系统注册,并不能解决所有报错。仍异常时请核对 macOS、宿主版本及安装包完整性;不要只复制单个 .moef 文件,配套程序与 Drop Zone.tiff 也需要保留。当前仅提供上述一个效果模板。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">源码与开源许可</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>公开源码仓库:<a href="https://github.com/dayumeida/FCP-BeautyGirl" target="_blank" rel="noreferrer noopener">GitHub · FCP-BeautyGirl</a>,可直接浏览源码、完整提交历史和版本标签。<a href="https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.1" target="_blank" rel="noreferrer noopener">1.3.1 Release</a> 提供正式签名公证安装包。大鱼站仓库作为备份保留:<a href="https://dayu.media/git/dayu/paintfcp-fxplug" target="_blank" rel="noreferrer noopener">paintfcp-fxplug</a>(该入口仍受站点登录与会员网关限制)。也可下载 <a href="https://dayu.media/wp-content/uploads/2026/10/1792659515-d487b0a421aacc6.zip">1.3.1 源码快照 ZIP</a>,源码与安装包均免费提供。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>项目代码按仓库中的 MIT 许可文件提供,源码包含 Xcode 工程、Objective-C / Metal 实现、模板及构建与验证说明。Apple SDK、运行框架及样本按各自许可使用,详见源码中的 LICENSE 和 THIRD_PARTY_NOTICES.md。自行编译需要 Xcode 与 FxPlug SDK;证书和签名私钥不包含在源码中。</p>
<!-- /wp:paragraph -->
<!-- wp:image {"id":15597,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://dayu.media/wp-content/uploads/2026/10/1792605142-78805a221a988e7-359x1024.png" alt="" class="wp-image-15597" /></figure>
<!-- /wp:image -->
+1 -1
查看文件
@@ -100,7 +100,7 @@
<!-- /wp:heading --> <!-- /wp:heading -->
<!-- wp:paragraph --> <!-- wp:paragraph -->
<p>公开源码仓库:<a href="https://github.com/FAMEDaYu/FCP-BeatyGril" target="_blank" rel="noreferrer noopener">GitHub · FCP-BeatyGril</a>,可直接浏览源码、完整提交历史和版本标签。<a href="https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.3.1" target="_blank" rel="noreferrer noopener">1.3.1 Release</a> 提供正式签名公证安装包。大鱼站仓库作为备份保留:<a href="https://dayu.media/git/dayu/paintfcp-fxplug" target="_blank" rel="noreferrer noopener">paintfcp-fxplug</a>(该入口仍受站点登录与会员网关限制)。也可下载 <a href="{{source_url}}">1.3.1 源码快照 ZIP</a>,源码与安装包均免费提供。</p> <p>公开源码仓库:<a href="https://github.com/dayumeida/FCP-BeautyGirl" target="_blank" rel="noreferrer noopener">GitHub · FCP-BeautyGirl</a>,可直接浏览源码、完整提交历史和版本标签。<a href="https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.1" target="_blank" rel="noreferrer noopener">1.3.1 Release</a> 提供正式签名公证安装包。大鱼站仓库作为备份保留:<a href="https://dayu.media/git/dayu/paintfcp-fxplug" target="_blank" rel="noreferrer noopener">paintfcp-fxplug</a>(该入口仍受站点登录与会员网关限制)。也可下载 <a href="{{source_url}}">1.3.1 源码快照 ZIP</a>,源码与安装包均免费提供。</p>
<!-- /wp:paragraph --> <!-- /wp:paragraph -->
<!-- wp:paragraph --> <!-- wp:paragraph -->
二进制文件未显示。
+19
查看文件
@@ -0,0 +1,19 @@
# FCP-BeautyGirl · 大鱼人像美化 1.3.2(17)
统一工程、APP、插件服务、源码类名和应用标识的拼写。主 Bundle ID 为 `com.dayu.fcpbeautygirl`,插件 ID 为 `com.dayu.fcpbeautygirl.fxplug`,唯一正式安装路径为 `/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app`。
安装器核对旧版的 Bundle ID、签名团队和滤镜 UUID 后迁移旧 APP;失败时恢复旧版,避免新旧服务并存。滤镜 UUID、参数编号和面板归档保留,渲染逻辑沿用 1.3.1。1901 项自动回归、8 项 APP 迁移测试、8 项安装器身份迁移测试,以及模板初装、更新与失败回滚隔离检查通过。更名后的旧工程重开与原生画面仍需用户实测。
- 文章:https://dayu.media/15593/
- GitHub:https://github.com/dayumeida/FCP-BeautyGirl
- 大鱼备份:https://dayu.media/git/dayu/paintfcp-fxplug
- 发布标签:v1.3.2
- 正式 APP 签名源码:767bba8ac11e9bf9268a1e02d1a06d3c120c46aa
- APP 公证:Accepted 559eedf0-048f-4d0e-b013-6a187695f2da
- PKG 公证:Accepted 4a831775-2317-4372-a4cc-102415657ea3
- PKG:FCP-BeautyGirl-1.3.2.pkg,4,889,706 bytes
- SHA-256:20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1
本机 PKG 工坊 CLI 生成基础包,加入本产品的旧身份迁移与回滚段后,对最终包重新签名、公证和粘附票据。包含用户指定的「大鱼磨皮瘦脸」分类:大鱼人像美化.moef、Drop Zone.tiff、large.png 和 small.png。有效载荷与正式 APP、四个模板文件一致;恢复两张缩略图的锁定。签名、公证票据、Gatekeeper 和隔离安装脚本核验通过,未实际运行本 PKG 安装器;本机 APP 已通过正式交付流程安装。
安装前保存并退出 Final Cut Pro 和 Motion。Final Cut Pro 在「效果 → 大鱼磨皮瘦脸 → 大鱼人像美化」中使用。免费开源,无需激活码。代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。Apple SDK 及相关资源遵循各自许可。
+44
查看文件
@@ -0,0 +1,44 @@
{
"title": "大鱼人像美化 1.3.2:FCP / Motion 免费开源自动美颜插件",
"status": "publish",
"content": "<!-- wp:paragraph -->\n<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>\n<!-- /wp:paragraph -->\n<!-- wp:paragraph -->\n<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604750-357ca780597c39f.png\" alt=\"大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜\" /><figcaption class=\"wp-element-caption\">古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>\n<!-- /wp:image -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">可以做什么</h2>\n<!-- /wp:heading -->\n\n<!-- wp:list {\"className\":\"wp-block-list\"} -->\n<ul class=\"wp-block-list\"><!-- wp:list-item -->\n<li>磨皮:磨皮程度、微细锐化、五官保护和非肤色区保护分别调节;全局磨皮与锐化保留在更多设置。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li>\n<!-- /wp:list-item --></ul>\n<!-- /wp:list -->\n\n<!-- wp:paragraph -->\n<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">版本与下载</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>当前版本 <strong>1.3.2(17)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>1.3.2 将工程、APP 与应用标识统一为 FCP-BeautyGirl;安装器会核对身份并迁移旧版程序,保留原滤镜 UUID 和参数存储格式。此版本沿用 1.3.1 的 V 脸下颌修复、微细锐化、连续五官保护和非肤色区保护。1901 项自动回归及安装迁移检查通过;本次更名后的旧工程重开与原生画面仍需结合实际素材检查。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">安装</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:image {\"sizeSlug\":\"full\"} -->\n<figure class=\"wp-block-image size-full\"><img src=\"https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png\" alt=\"主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出\" /></figure>\n<!-- /wp:image -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">使用</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观Line truncated
"excerpt": "1.3.2 将工程、APP 与应用 ID 统一为 FCP-BeautyGirl,安装自动迁移旧版。保留 V 脸下颌修复和磨皮参数,提供免费开源源码及签名公证安装包。",
"seo": {
"title": {
"enabled": true,
"value": "大鱼人像美化 1.3.2|FCP / Motion 免费开源自动美颜插件"
},
"description": {
"enabled": true,
"value": "大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件。1.3.2 将工程、APP 和应用 ID 统一为 FCP-BeautyGirl,自动迁移旧版;保留 V 脸下颌修复及磨皮保护参数。提供 Apple 签名公证安装包和源码,无需激活码,附安装使用说明。"
},
"keywords": {
"enabled": true,
"value": "大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源"
}
},
"resource": {
"cao_info": [
{
"title": "版本",
"desc": "1.3.2(17)"
},
{
"title": "宿主",
"desc": "Final Cut Pro / Motion"
},
{
"title": "系统",
"desc": "macOS 13 或更高版本"
},
{
"title": "架构",
"desc": "Apple Silicon / Intel"
},
{
"title": "授权",
"desc": "免费开源,无需激活码"
}
]
}
}
+112
查看文件
@@ -0,0 +1,112 @@
<!-- wp:paragraph -->
<p>大鱼人像美化是一款适用于 Final Cut Pro 与 Motion 的免费开源人像插件,把磨皮、美白和脸型调整放进同一块原生卡片面板。插件会识别当前画面中的人脸并自动跟随,无需先点击分析;你可以按素材需要调整强度,拖动滑杆时持续查看效果。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p><strong>代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。</strong></p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"full"} -->
<figure class="wp-block-image size-full"><img src="https://dayu.media/wp-content/uploads/2026/10/1792604750-357ca780597c39f.png" alt="大鱼人像美化古风宣传封面,展示自动瘦脸、自动跟随与自动美颜" /><figcaption class="wp-element-caption">古风宣传插画;面部线条用于示意瘦脸与跟随功能。</figcaption></figure>
<!-- /wp:image -->
<!-- wp:heading -->
<h2 class="wp-block-heading">可以做什么</h2>
<!-- /wp:heading -->
<!-- wp:list {"className":"wp-block-list"} -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>磨皮:磨皮程度、微细锐化、五官保护和非肤色区保护分别调节;全局磨皮与锐化保留在更多设置。</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>美白:肤色预设、肤色亮度、皮肤色相和牙齿美白。</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>脸型:瘦脸、大眼、短脸、窄脸、下巴、V 脸、下颌骨、颧骨与小头调整。</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>自动跟随:默认跟随主要人脸,也提供多人模式、防跳脸范围与检测框预览。</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>实时预览:滑杆、数值、单项开关和重置集中在同一面板,便于反复对比。</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->
<!-- wp:paragraph -->
<p>自动识别负责定位处理区域,效果强度由你控制。建议先从较小的数值开始;多人交叉、严重遮挡和极端侧脸的结果需要结合具体素材检查。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">版本与下载</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>当前版本 <strong>1.3.2(17)</strong>,支持 macOS 13 或更高版本,包含 Apple Silicon 与 Intel 两种架构。下载包包含 FxPlug4 程序和一个配套 FCP 效果模板。APP 与 PKG 均已完成 Developer ID 正式签名、Apple 公证和票据粘附;安装包为所有用户免费资源。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>1.3.2 将工程、APP 与应用标识统一为 FCP-BeautyGirl;安装器会核对身份并迁移旧版程序,保留原滤镜 UUID 和参数存储格式。此版本沿用 1.3.1 的 V 脸下颌修复、微细锐化、连续五官保护和非肤色区保护。1901 项自动回归及安装迁移检查通过;本次更名后的旧工程重开与原生画面仍需结合实际素材检查。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">安装</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>安装前先保存工作并退出 Final Cut Pro 和 Motion,安装期间保持关闭。运行本页提供的 PKG,按安装器提示完成安装;它会把程序安装到 <code>/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app</code>,把配套效果安装到当前登录用户的 Motion Templates 目录,并自动验证和修复系统插件注册。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>本插件免费开源,<strong>无需激活码、付费注册或账号授权</strong>。主 APP 打开时显示说明图,窗口显示三秒后自动退出;宿主中的滤镜由独立服务运行。安装器还会重新锁定两张缩略图,避免被宿主自动替换。</p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"full"} -->
<figure class="wp-block-image size-full"><img src="https://dayu.media/wp-content/uploads/2026/10/1792604743-1c99c2ba53c7614.png" alt="主程序说明页:免费开源,自动注册,无需激活码,启动三秒后自动退出" /></figure>
<!-- /wp:image -->
<!-- wp:heading -->
<h2 class="wp-block-heading">使用</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Final Cut Pro:打开<strong>效果</strong>浏览器,找到<strong>大鱼磨皮瘦脸</strong>分类,将<strong>大鱼人像美化</strong>添加到人像片段。Motion:在原生滤镜资源库的<strong>大鱼</strong>分类中选择<strong>大鱼人像美化</strong>。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>在检查器中按需调节磨皮、美白和脸型。每项左侧的眼睛可暂时停用该项,数值会保留;右侧回转箭头用于重置。人脸会随画面自动更新,开启检测框预览可以检查跟随位置。多人模式建议先用短片段观察稳定性。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">常见问题</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>如果效果没有出现或显示红色警告,先退出 Final Cut Pro 和 Motion,再打开一次主 APP,等待其自动退出,然后重新启动宿主。可在“终端”执行下面这条命令:</p>
<!-- /wp:paragraph -->
<!-- wp:code -->
<pre class="wp-block-code"><code>open '/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app'</code></pre>
<!-- /wp:code -->
<!-- wp:paragraph -->
<p>该流程可重新触发系统注册,并不能解决所有报错。仍异常时请核对 macOS、宿主版本及安装包完整性;不要只复制单个 .moef 文件,配套程序与 Drop Zone.tiff 也需要保留。当前仅提供上述一个效果模板。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">源码与开源许可</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>公开源码仓库:<a href="https://github.com/dayumeida/FCP-BeautyGirl" target="_blank" rel="noreferrer noopener">GitHub · FCP-BeautyGirl</a>,可直接浏览源码、完整提交历史和版本标签。<a href="https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.2" target="_blank" rel="noreferrer noopener">1.3.2 Release</a> 提供正式签名公证安装包。大鱼站仓库作为备份保留:<a href="https://dayu.media/git/dayu/paintfcp-fxplug" target="_blank" rel="noreferrer noopener">paintfcp-fxplug</a>(该入口仍受站点登录与会员网关限制)。也可下载 <a href="{{source_url}}">1.3.2 源码快照 ZIP</a>,源码与安装包均免费提供。</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>项目代码按仓库中的 MIT 许可文件提供,源码包含 Xcode 工程、Objective-C / Metal 实现、模板及构建与验证说明。Apple SDK、运行框架及样本按各自许可使用,详见源码中的 LICENSE 和 THIRD_PARTY_NOTICES.md。自行编译需要 Xcode 与 FxPlug SDK;证书和签名私钥不包含在源码中。</p>
<!-- /wp:paragraph -->
<!-- wp:image {"id":15597,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://dayu.media/wp-content/uploads/2026/10/1792605142-78805a221a988e7-359x1024.png" alt="" class="wp-image-15597" /></figure>
<!-- /wp:image -->
+20 -18
查看文件
@@ -3,26 +3,24 @@
The final prompt keeps the lock held while native-host validation is performed. The final prompt keeps the lock held while native-host validation is performed.
""" """
import argparse, datetime, json, os, pathlib, plistlib, re, shutil, subprocess, sys, time import argparse, datetime, json, os, pathlib, plistlib, re, shutil, subprocess, sys, time
from product_identity import PRODUCT, LegacyMigration, delivery_locks, validate_app
root=pathlib.Path(__file__).resolve().parent.parent root=pathlib.Path(__file__).resolve().parent.parent
parser=argparse.ArgumentParser(description=__doc__) parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--wait-for-hosts',action='store_true',help='After notarization, retain the delivery lock and wait for Motion/FCP to exit naturally before installing; never control or quit either host.') parser.add_argument('--wait-for-hosts',action='store_true',help='After notarization, retain the delivery lock and wait for Motion/FCP to exit naturally before installing; never control or quit either host.')
parser.add_argument('--user-tests',action='store_true',help='After non-UI installed-app verification, record native effect QA as pending user testing and clean known generated copies without the interactive validation prompt.') parser.add_argument('--user-tests',action='store_true',help='After non-UI installed-app verification, record native effect QA as pending user testing and clean known generated copies without the interactive validation prompt.')
parser.add_argument('--resume-prepared',action='store_true',help='Resume an already Accepted and stapled staged app after checking its recorded signature, version and unchanged product source.') parser.add_argument('--resume-prepared',action='store_true',help='Resume an already Accepted and stapled staged app after checking its recorded signature, version and unchanged product source.')
args=parser.parse_args() args=parser.parse_args()
bundle_id='com.dayu.beatygril' bundle_id=PRODUCT['bundleIdentifier']
lock=pathlib.Path('/Users/dayu/.codex/app-delivery-locks')/(bundle_id+'.lock') locks=delivery_locks();locks.__enter__()
lock.parent.mkdir(parents=True,exist_ok=True) staging=pathlib.Path('/tmp/fcp-beautygirl-release')
try:lock.mkdir()
except FileExistsError:raise SystemExit('Delivery lock occupied; inspect owner.json and the owner process')
(lock/'owner.json').write_text(json.dumps({'pid':os.getpid(),'cwd':str(root),'bundle_id':bundle_id}))
staging=pathlib.Path('/tmp/paintfcp-build-20261021')
logs=root/'build'/'delivery';logs.mkdir(parents=True,exist_ok=True) logs=root/'build'/'delivery';logs.mkdir(parents=True,exist_ok=True)
app=staging/'Build/Products/Release/beatygril.app' app=staging/'Build/Products/Release'/(PRODUCT['name']+'.app')
installed=pathlib.Path('/Library/Plug-Ins/FxPlug/beatygril.app') installed=pathlib.Path(PRODUCT['installationPath'])
archive=logs/'notarization.zip' archive=logs/'notarization.zip'
identity='Developer ID Application: zhong luo (B3W25FX5H5)' identity='Developer ID Application: zhong luo (B3W25FX5H5)'
keychain='/Users/dayu/Library/Keychains/login.keychain-db' keychain='/Users/dayu/Library/Keychains/login.keychain-db'
previous=logs/'previous-beatygril.app' previous=logs/'previous-FCP-BeautyGirl.app'
migration=LegacyMigration(logs)
receipt_path=logs/'delivery-receipt.json' receipt_path=logs/'delivery-receipt.json'
receipt={'status':'preparing','bundleIdentifier':bundle_id,'installationPath':str(installed), receipt={'status':'preparing','bundleIdentifier':bundle_id,'installationPath':str(installed),
'options':{'waitForHosts':args.wait_for_hosts,'userTests':args.user_tests}, 'options':{'waitForHosts':args.wait_for_hosts,'userTests':args.user_tests},
@@ -80,7 +78,7 @@ def cleanup_known_products():
try: try:
delivery_source={'commit':run(['git','rev-parse','HEAD']).strip(), delivery_source={'commit':run(['git','rev-parse','HEAD']).strip(),
'trackedWorktreeChanges':run(['git','status','--porcelain','--untracked-files=no']).splitlines()} 'trackedWorktreeChanges':run(['git','status','--porcelain','--untracked-files=no']).splitlines()}
plugin=app/'Contents/PlugIns/beatygril XPC Service.pluginkit' plugin=app/'Contents/PlugIns'/PRODUCT['pluginName']
if args.resume_prepared: if args.resume_prepared:
old_receipt=json.loads(receipt_path.read_text()) old_receipt=json.loads(receipt_path.read_text())
result=old_receipt.get('notarization',{}) result=old_receipt.get('notarization',{})
@@ -94,7 +92,7 @@ try:
if not expected or not actual or expected.group(1)!=actual.group(1):raise RuntimeError('Prepared signature hash changed') if not expected or not actual or expected.group(1)!=actual.group(1):raise RuntimeError('Prepared signature hash changed')
if info.get('CFBundleShortVersionString')!=old_receipt.get('version') or info.get('CFBundleVersion')!=old_receipt.get('build'):raise RuntimeError('Prepared version changed') if info.get('CFBundleShortVersionString')!=old_receipt.get('version') or info.get('CFBundleVersion')!=old_receipt.get('build'):raise RuntimeError('Prepared version changed')
source_commit=old_receipt.get('source',{}).get('commit') source_commit=old_receipt.get('source',{}).get('commit')
if not source_commit or run(['git','diff',source_commit,'--','beatygril']).strip():raise RuntimeError('Product source changed since prepared build') if not source_commit or run(['git','diff',source_commit,'--',PRODUCT['sourceRoot'],'product.json']).strip():raise RuntimeError('Product source changed since prepared build')
receipt.update(old_receipt);receipt.pop('failure',None) receipt.update(old_receipt);receipt.pop('failure',None)
receipt['resumedBy']=delivery_source receipt['resumedBy']=delivery_source
receipt['options']={'waitForHosts':args.wait_for_hosts,'userTests':args.user_tests,'resumePrepared':True} receipt['options']={'waitForHosts':args.wait_for_hosts,'userTests':args.user_tests,'resumePrepared':True}
@@ -107,14 +105,14 @@ try:
identities=run(['security','find-identity','-v','-p','codesigning',keychain]) identities=run(['security','find-identity','-v','-p','codesigning',keychain])
if identity not in identities:raise RuntimeError('Valid Developer ID Application identity is unavailable') if identity not in identities:raise RuntimeError('Valid Developer ID Application identity is unavailable')
print('Building universal Release…',flush=True) print('Building universal Release…',flush=True)
run(['xcodebuild','-project','beatygril/beatygril.xcodeproj','-scheme','Wrapper Application','-configuration','Release','-derivedDataPath',str(staging),'-destination','generic/platform=macOS','build'],logs/'build.log') run(['xcodebuild','-project',PRODUCT['xcodeProject'],'-scheme',PRODUCT['scheme'],'-configuration','Release','-derivedDataPath',str(staging),'-destination','generic/platform=macOS','build'],logs/'build.log')
# Xcode can register a fresh build. Remove this known generated path before # Xcode can register a fresh build. Remove this known generated path before
# lengthy signing/notarization while a user may still be testing the old app. # lengthy signing/notarization while a user may still be testing the old app.
unregister_generated_plugin(plugin) unregister_generated_plugin(plugin)
for framework in sorted((plugin/'Contents/Frameworks').glob('*.framework')): for framework in sorted((plugin/'Contents/Frameworks').glob('*.framework')):
run(['codesign','--force','--timestamp','--options','runtime','--sign',identity,str(framework)]) run(['codesign','--force','--timestamp','--options','runtime','--sign',identity,str(framework)])
run(['codesign','--force','--timestamp','--options','runtime','--sign',identity,str(plugin)]) run(['codesign','--force','--timestamp','--options','runtime','--sign',identity,str(plugin)])
run(['codesign','--force','--timestamp','--options','runtime','--entitlements',str(root/'beatygril/beatygril/Wrapper Application/SandboxEntitlements.entitlements'),'--sign',identity,str(app)]) run(['codesign','--force','--timestamp','--options','runtime','--entitlements',str(root/PRODUCT['sourceDirectory']/'Wrapper Application/SandboxEntitlements.entitlements'),'--sign',identity,str(app)])
run(['codesign','--verify','--deep','--strict',str(app)]) run(['codesign','--verify','--deep','--strict',str(app)])
info=require_product(app) info=require_product(app)
receipt['version']=info.get('CFBundleShortVersionString');receipt['build']=info.get('CFBundleVersion') receipt['version']=info.get('CFBundleShortVersionString');receipt['build']=info.get('CFBundleVersion')
@@ -148,6 +146,8 @@ try:
if installed.exists(): if installed.exists():
shutil.move(str(installed),str(previous)) shutil.move(str(installed),str(previous))
try: try:
validate_app(app,bundle_id)
migration.relocate(unregister_generated_plugin)
shutil.copytree(app,installed,symlinks=True) shutil.copytree(app,installed,symlinks=True)
run(['codesign','--verify','--deep','--strict',str(installed)]) run(['codesign','--verify','--deep','--strict',str(installed)])
run(['xcrun','stapler','validate',str(installed)]) run(['xcrun','stapler','validate',str(installed)])
@@ -156,21 +156,23 @@ try:
signature=subprocess.run(['codesign','-dvvv',str(installed)],capture_output=True,text=True,check=True).stderr signature=subprocess.run(['codesign','-dvvv',str(installed)],capture_output=True,text=True,check=True).stderr
if info.get('CFBundleIdentifier')!=bundle_id or 'TeamIdentifier=B3W25FX5H5' not in signature:raise RuntimeError('Installed app identity mismatch') if info.get('CFBundleIdentifier')!=bundle_id or 'TeamIdentifier=B3W25FX5H5' not in signature:raise RuntimeError('Installed app identity mismatch')
(logs/'installed-signature.txt').write_text(signature) (logs/'installed-signature.txt').write_text(signature)
run(['pluginkit','-a',str(installed/'Contents/PlugIns/beatygril XPC Service.pluginkit')]) run(['pluginkit','-a',str(installed/'Contents/PlugIns'/PRODUCT['pluginName'])])
# Xcode may register its build product. Only the installed plugin should # Xcode may register its build product. Only the installed plugin should
# be discoverable while native host validation is in progress. # be discoverable while native host validation is in progress.
unregister_generated_plugin(plugin) unregister_generated_plugin(plugin)
installed_plugin=installed/'Contents/PlugIns/beatygril XPC Service.pluginkit' installed_plugin=installed/'Contents/PlugIns'/PRODUCT['pluginName']
plugin_info=plistlib.loads((installed_plugin/'Contents/Info.plist').read_bytes()) plugin_info=plistlib.loads((installed_plugin/'Contents/Info.plist').read_bytes())
discovered=run(['pluginkit','-m','-A','-D','-v','-i',plugin_info['CFBundleIdentifier']]) discovered=run(['pluginkit','-m','-A','-D','-v','-i',plugin_info['CFBundleIdentifier']])
if str(installed_plugin) not in discovered:raise RuntimeError('PluginKit did not report the formal installed plug-in path') if str(installed_plugin) not in discovered:raise RuntimeError('PluginKit did not report the formal installed plug-in path')
(logs/'installed-discovery.txt').write_text(discovered) (logs/'installed-discovery.txt').write_text(discovered)
save_receipt('installed',installedSignature=signature,installedSignatureVerified=True, save_receipt('installed',installedSignature=signature,installedSignatureVerified=True,
installedStapleValidated=True,gatekeeperAccepted=True, installedStapleValidated=True,gatekeeperAccepted=True,
identityMigration={'legacyInstallationsRemoved':[str(source) for legacy,source,backup in migration.moved], 'filterUUIDPreserved':PRODUCT['filterUUID']},
pluginDiscovery={'bundleIdentifier':plugin_info['CFBundleIdentifier'],'formalPath':str(installed_plugin),'output':discovered}) pluginDiscovery={'bundleIdentifier':plugin_info['CFBundleIdentifier'],'formalPath':str(installed_plugin),'output':discovered})
except Exception: except Exception:
if installed.exists():shutil.rmtree(installed) if installed.exists():shutil.rmtree(installed)
if previous.exists():shutil.move(str(previous),str(installed)) if previous.exists():shutil.move(str(previous),str(installed))
migration.rollback(lambda path:run(['pluginkit','-a',str(path)]))
raise raise
print(json.dumps({'status':'installed','path':str(installed),'notarization':result}),flush=True) print(json.dumps({'status':'installed','path':str(installed),'notarization':result}),flush=True)
if args.user_tests: if args.user_tests:
@@ -179,11 +181,11 @@ try:
input('HOST_VALIDATION_PENDING: press Return only after host verification and duplicate inventory.\n') input('HOST_VALIDATION_PENDING: press Return only after host verification and duplicate inventory.\n')
receipt['nativeEffectQA']={'status':'operator_confirmed','performedByScript':False} receipt['nativeEffectQA']={'status':'operator_confirmed','performedByScript':False}
# Only this task’s known generated product copies are removed. # Only this task’s known generated product copies are removed.
removed=cleanup_known_products() removed=migration.cleanup()+cleanup_known_products()
save_receipt('installed_user_qa_pending' if args.user_tests else 'complete',removedGeneratedPaths=removed) save_receipt('installed_user_qa_pending' if args.user_tests else 'complete',removedGeneratedPaths=removed)
print('Delivery staging and notarization archive cleaned.',flush=True) print('Delivery staging and notarization archive cleaned.',flush=True)
except BaseException as error: except BaseException as error:
save_receipt('failed',failure={'type':type(error).__name__,'message':str(error)}) save_receipt('failed',failure={'type':type(error).__name__,'message':str(error)})
raise raise
finally: finally:
(lock/'owner.json').unlink();lock.rmdir() locks.__exit__(None,None,None)
+83
查看文件
@@ -0,0 +1,83 @@
"""Add this product's reversible identity migration to PKG Forge's postinstall."""
from product_identity import PRODUCT
def inject_migration(post, product=PRODUCT):
legacy, = product['legacyProducts']
block = r'''
# FCP-BeautyGirl identity migration. Payload and template work are already complete.
BG_NEW_APP="${TARGET_VOLUME%/}@@NEW_PATH@@"
BG_OLD_APP="${TARGET_VOLUME%/}@@OLD_PATH@@"
BG_BACKUP_DIR=""
BG_OLD_MOVED=0
bg_validate_identity() {
local app="$1" expected="$2" plugin="$3" actual signature uuid
[[ -d "$app" && ! -L "$app" ]] || return 1
actual="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$app/Contents/Info.plist")" || return 1
[[ "$actual" == "$expected" ]] || return 1
/usr/bin/codesign --verify --all-architectures --deep --strict "$app" || return 1
signature="$(/usr/bin/codesign -dvvv "$app" 2>&1)" || return 1
[[ "$signature" == *'TeamIdentifier=@@TEAM@@'* ]] || return 1
uuid="$(/usr/libexec/PlistBuddy -c 'Print :ProPlugPlugInList:0:uuid' "$app/Contents/PlugIns/$plugin/Contents/Info.plist")" || return 1
[[ "$uuid" == '@@UUID@@' ]]
}
bg_unregister_identity() {
# Both bootstrap session and Unix identity belong to the desktop user.
/bin/launchctl asuser "$CONSOLE_UID" /usr/bin/sudo -u "$CONSOLE_USER" /usr/bin/pluginkit -r "$1" >/dev/null 2>&1 || true
}
bg_rollback_identity() {
local result=$?
trap - EXIT
if (( result != 0 && BG_OLD_MOVED )); then
bg_validate_identity "$BG_NEW_APP" '@@NEW_ID@@' '@@NEW_PLUGIN@@' || {
/bin/echo "新 APP 身份已变化,旧版保留在 $BG_BACKUP_DIR" >&2
exit "$result"
}
bg_unregister_identity "$BG_NEW_APP/Contents/PlugIns/@@NEW_PLUGIN@@"
/bin/rm -rf "$BG_NEW_APP"
/bin/mv "$BG_BACKUP_DIR/@@OLD_NAME@@.app" "$BG_OLD_APP"
/bin/rmdir "$BG_BACKUP_DIR"
fx_verify_app "$BG_OLD_APP" 0 'Contents/PlugIns/@@OLD_PLUGIN@@' '@@OLD_PLUGIN_ID@@' '1.1' || true
fi
exit "$result"
}
bg_finish_identity() {
if (( BG_OLD_MOVED )); then
bg_validate_identity "$BG_BACKUP_DIR/@@OLD_NAME@@.app" '@@OLD_ID@@' '@@OLD_PLUGIN@@'
/bin/rm -rf "$BG_BACKUP_DIR/@@OLD_NAME@@.app"
/bin/rmdir "$BG_BACKUP_DIR"
fi
trap - EXIT
}
bg_validate_identity "$BG_NEW_APP" '@@NEW_ID@@' '@@NEW_PLUGIN@@' || {
/bin/echo '新版 APP 签名或身份验证失败,未迁移旧版。' >&2
exit 1
}
if [[ -e "$BG_OLD_APP" || -L "$BG_OLD_APP" ]]; then
bg_validate_identity "$BG_OLD_APP" '@@OLD_ID@@' '@@OLD_PLUGIN@@' || {
/bin/echo '旧路径的 APP 身份不属于本产品,未移动或删除。' >&2
exit 1
}
BG_RECOVERY_ROOT="${TARGET_VOLUME%/}/Library/Application Support/@@NAME@@/Migration"
/bin/mkdir -p "$BG_RECOVERY_ROOT"
BG_BACKUP_DIR="$(/usr/bin/mktemp -d "$BG_RECOVERY_ROOT/.upgrade-XXXXXXXX")"
bg_unregister_identity "$BG_OLD_APP/Contents/PlugIns/@@OLD_PLUGIN@@"
/bin/mv "$BG_OLD_APP" "$BG_BACKUP_DIR/@@OLD_NAME@@.app"
BG_OLD_MOVED=1
fi
trap bg_rollback_identity EXIT
'''
values = {'NEW_PATH': product['installationPath'], 'OLD_PATH': legacy['installationPath'],
'NEW_ID': product['bundleIdentifier'], 'OLD_ID': legacy['bundleIdentifier'],
'NEW_PLUGIN': product['pluginName'], 'OLD_PLUGIN': legacy['pluginName'],
'OLD_PLUGIN_ID': legacy['pluginBundleIdentifier'], 'OLD_NAME': legacy['name'],
'NAME': product['name'], 'TEAM': product['teamIdentifier'], 'UUID': product['filterUUID']}
for key, value in values.items():
if any(c in value for c in ['"', "'", '\n', '$', '`']):
raise ValueError('Unsafe installer identity value: ' + key)
block = block.replace('@@' + key + '@@', value)
marker = '\ntrap - EXIT\nfx_verify_app '
if post.count(marker) != 1 or not post.rstrip().endswith('exit 0'):
raise ValueError('Unexpected PKG Forge postinstall structure')
post = post.replace(marker, '\ntrap - EXIT\n' + block + '\nfx_verify_app ', 1)
end = post.rfind('exit 0')
return post[:end] + 'bg_finish_identity\n' + post[end:]
+104
查看文件
@@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""Package the installed product with local PKG Forge, then sign/notarize its migration update."""
import argparse, datetime, hashlib, json, os, pathlib, plistlib, shutil, subprocess, sys
from installer_identity import inject_migration
from product_identity import PRODUCT, ROOT, delivery_locks, validate_app
def run(args, log=None, env=None):
result = subprocess.run(args, cwd=ROOT, text=True, capture_output=True, env=env)
if log:
pathlib.Path(log).write_text(result.stdout + result.stderr)
result.check_returncode()
return result.stdout
version = PRODUCT['version']
work = ROOT / 'build' / ('package-' + version)
release = ROOT / 'releases' / version
proof = ROOT / 'docs/verification' / ('v' + version)
package_name = PRODUCT['name'] + '-' + version + '.pkg'
final = release / package_name
keychain = '/Users/dayu/Library/Keychains/login.keychain-db'
installer_identity = 'Developer ID Installer: zhong luo (B3W25FX5H5)'
cli = '/Applications/PKG工坊.app/Contents/MacOS/PKG工坊'
source_template = pathlib.Path('/Users/dayu/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸')
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--verify-existing', action='store_true', help='Resume verification of the already Accepted, stapled final package without rebuilding or resubmitting it.')
args = parser.parse_args()
with delivery_locks():
if not args.verify_existing:
if work.exists() or final.exists():
raise SystemExit('Packaging work or final package already exists; inspect before retrying')
work.mkdir(parents=True)
release.mkdir(parents=True, exist_ok=True)
proof.mkdir(parents=True, exist_ok=True)
formal = pathlib.Path(PRODUCT['installationPath'])
info = validate_app(formal, PRODUCT['bundleIdentifier'])
assert info['CFBundleShortVersionString'] == version and info['CFBundleVersion'] == PRODUCT['build']
assert installer_identity in run(['security', 'find-identity', '-v', '-p', 'basic', keychain])
template = work / 'input/大鱼磨皮瘦脸'
manifest = []
for source in sorted(source_template.rglob('*')):
if source.is_file() and source.name != '.DS_Store':
target = template / source.relative_to(source_template)
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source, target)
if source.stat().st_flags & 2:
run(['chflags', 'uchg', str(target)])
manifest.append({'file': str(source.relative_to(source_template)), 'sha256': hashlib.sha256(source.read_bytes()).hexdigest(), 'locked': bool(source.stat().st_flags & 2)})
assert len(manifest) == 4 and len(list(template.rglob('*.moef'))) == 1
base = work / 'base' / package_name
base.parent.mkdir()
print('PKG Forge: generating signed/notarized base installer from the formal APP and installed Motion category.', flush=True)
run([cli, 'inspect', str(formal), str(template)], proof / 'pkgforge-inspect.txt')
run([cli, 'package', '--name', PRODUCT['name'], '--version', version, '--identifier-prefix', 'com.dayu.fcppackage', '--signing-identity', installer_identity, '--notary-profile', 'codex-dayu-notary-B3W25FX5H5', '--keychain', keychain, '--output', str(base), str(formal), str(template)], proof / 'pkgforge.txt')
run(['pkgutil', '--check-signature', str(base)])
run(['xcrun', 'stapler', 'validate', str(base)])
expanded = work / 'expanded'
run(['pkgutil', '--expand', str(base), str(expanded)])
script = expanded / 'Payload.pkg/Scripts/postinstall'
script.write_text(inject_migration(script.read_text()))
run(['/bin/zsh', '-n', str(script)])
# PKG Forge owns the payload/template/update scripts. Only the product's
# identity migration is added, then the complete result is signed afresh.
unsigned = work / 'migration-unsigned.pkg'
run(['pkgutil', '--flatten', str(expanded), str(unsigned)])
run(['productsign', '--sign', installer_identity, '--keychain', keychain, '--timestamp', str(unsigned), str(final)], proof / 'pkg-signing.txt')
print('Submitting the final migration installer to Apple notarization.', flush=True)
result = json.loads(run(['xcrun', 'notarytool', 'submit', str(final), '--keychain-profile', 'codex-dayu-notary-B3W25FX5H5', '--keychain', keychain, '--wait', '--output-format', 'json']))
(proof / 'pkg-notarization.json').write_text(json.dumps(result, indent=2) + '\n')
if result.get('status') != 'Accepted':
raise RuntimeError('Final migration package notarization was not Accepted')
run(['xcrun', 'stapler', 'staple', str(final)], proof / 'pkg-staple.txt')
run(['xcrun', 'stapler', 'validate', str(final)])
run(['pkgutil', '--check-signature', str(final)], proof / 'pkg-signature.txt')
run(['spctl', '-a', '-vv', '-t', 'install', str(final)], proof / 'pkg-gatekeeper.txt')
else:
if not work.exists() or not final.exists():
raise RuntimeError('No prepared package to verify')
formal = pathlib.Path(PRODUCT['installationPath'])
info = validate_app(formal, PRODUCT['bundleIdentifier'])
assert info['CFBundleShortVersionString'] == version and info['CFBundleVersion'] == PRODUCT['build']
result = json.loads((proof / 'pkg-notarization.json').read_text())
assert result['status'] == 'Accepted'
run(['xcrun', 'stapler', 'validate', str(final)])
run(['pkgutil', '--check-signature', str(final)])
run(['spctl', '-a', '-vv', '-t', 'install', str(final)])
template = work / 'input/大鱼磨皮瘦脸'
manifest = [{'file': str(p.relative_to(template)), 'sha256': hashlib.sha256(p.read_bytes()).hexdigest(), 'locked': bool(p.stat().st_flags & 2)} for p in sorted(template.rglob('*')) if p.is_file()]
assert len(manifest) == 4
full = work / 'full'
try:
run(['pkgutil', '--expand-full', str(final), str(full)])
run([sys.executable, 'scripts/verify-release-package.py', '--version', version, '--build', PRODUCT['build'], '--expanded', str(full), '--fixture', 'build/pkg-isolation-' + version], proof / 'pkg-verification-output.txt')
env = dict(os.environ, FCP_BEAUTYGIRL_POSTINSTALL=str(full / 'Payload.pkg/Scripts/postinstall'))
run([sys.executable, 'tests/installer_identity_tests.py'], proof / 'installer-tests.txt', env=env)
finally:
if full.exists():
run(['chflags', '-R', 'nouchg', str(full)])
shutil.rmtree(full)
receipt = {'status': 'verified', 'version': version, 'build': PRODUCT['build'], 'package': str(final.relative_to(ROOT)), 'bytes': final.stat().st_size, 'sha256': hashlib.sha256(final.read_bytes()).hexdigest(), 'sourceApp': str(formal), 'sourceCommit': json.loads((ROOT / 'build/delivery/delivery-receipt.json').read_text())['source']['commit'], 'motionSource': str(source_template), 'motionFiles': manifest, 'packager': cli, 'productMigration': 'PKG Forge base plus identity-checked backup/rollback block; final package freshly signed, notarized and stapled', 'notarization': result, 'realInstallerExecuted': False}
(proof / 'pkg-delivery.json').write_text(json.dumps(receipt, ensure_ascii=False, indent=2) + '\n')
run(['chflags', '-R', 'nouchg', str(work)])
shutil.rmtree(work)
print(json.dumps(receipt, ensure_ascii=False), flush=True)
+81
查看文件
@@ -0,0 +1,81 @@
"""Shared product identity and reversible, identity-checked legacy APP migration."""
import contextlib, json, os, pathlib, plistlib, shutil, subprocess
ROOT = pathlib.Path(__file__).resolve().parent.parent
PRODUCT = json.loads((ROOT / 'product.json').read_text())
def validate_app(path, bundle_id, team=PRODUCT['teamIdentifier']):
path = pathlib.Path(path)
info = plistlib.loads((path / 'Contents/Info.plist').read_bytes())
if info.get('CFBundleIdentifier') != bundle_id:
raise RuntimeError('APP identity mismatch: ' + str(path))
subprocess.run(['codesign', '--verify', '--all-architectures', '--deep', '--strict', str(path)], check=True, capture_output=True)
signature = subprocess.run(['codesign', '-dvvv', str(path)], check=True, text=True, capture_output=True).stderr
if ('TeamIdentifier=' + team) not in signature:
raise RuntimeError('APP signing team mismatch: ' + str(path))
plugins = list((path / 'Contents/PlugIns').glob('*.pluginkit'))
if not any(PRODUCT['filterUUID'] in [p.get('uuid') for p in plistlib.loads((plugin / 'Contents/Info.plist').read_bytes()).get('ProPlugPlugInList', [])] for plugin in plugins):
raise RuntimeError('APP does not contain this product filter UUID: ' + str(path))
return info
@contextlib.contextmanager
def delivery_locks(product=PRODUCT):
"""Hold both old and new identity locks throughout an identity migration."""
base = pathlib.Path('/Users/dayu/.codex/app-delivery-locks')
base.mkdir(parents=True, exist_ok=True)
held = []
try:
for bundle_id in sorted({product['bundleIdentifier']} | {p['bundleIdentifier'] for p in product.get('legacyProducts', [])}):
lock = base / (bundle_id + '.lock')
lock.mkdir()
held.append(lock)
(lock / 'owner.json').write_text(json.dumps({'pid': os.getpid(), 'cwd': str(ROOT), 'bundle_id': bundle_id, 'product': product['name']}))
yield
finally:
for lock in reversed(held):
(lock / 'owner.json').unlink(missing_ok=True)
lock.rmdir()
class LegacyMigration:
def __init__(self, backup_root, *, product=PRODUCT, volume=pathlib.Path('/'), verifier=validate_app):
self.product, self.backup_root, self.verifier = product, pathlib.Path(backup_root), verifier
self.volume, self.moved = pathlib.Path(volume), []
def candidates(self):
result = []
for legacy in self.product.get('legacyProducts', []):
source = self.volume / pathlib.Path(legacy['installationPath']).relative_to('/')
if source.exists():
self.verifier(source, legacy['bundleIdentifier'])
backup = self.backup_root / ('legacy-' + legacy['name'] + '.app')
if backup.exists():
raise RuntimeError('Legacy recovery copy already exists: ' + str(backup))
result.append((legacy, source, backup))
return result
def relocate(self, unregister):
# Validate every candidate before moving any of them.
for legacy, source, backup in self.candidates():
self.verifier(source, legacy['bundleIdentifier'])
unregister(source / 'Contents/PlugIns' / legacy['pluginName'])
backup.parent.mkdir(parents=True, exist_ok=True)
shutil.move(str(source), str(backup))
self.moved.append((legacy, source, backup))
def rollback(self, register):
for legacy, source, backup in reversed(self.moved):
if source.exists():
raise RuntimeError('Refusing to overwrite a new APP during rollback: ' + str(source))
self.verifier(backup, legacy['bundleIdentifier'])
shutil.move(str(backup), str(source))
register(source / 'Contents/PlugIns' / legacy['pluginName'])
self.moved.clear()
def cleanup(self):
removed = []
for legacy, source, backup in self.moved:
self.verifier(backup, legacy['bundleIdentifier'])
shutil.rmtree(backup)
removed.append(str(backup))
self.moved.clear()
return removed
+1 -1
查看文件
@@ -38,7 +38,7 @@ with zipfile.ZipFile(source_zip) as z:
assert z.testzip() is None and any(n.endswith('/Wrapper Application/AppDelegate.m') for n in z.namelist()) assert z.testzip() is None and any(n.endswith('/Wrapper Application/AppDelegate.m') for n in z.namelist())
status=request('/dayu-publisher/v1/status');assert status['can_publish'] and status['can_upload'] and 'seo' in status['fields'] status=request('/dayu-publisher/v1/status');assert status['can_publish'] and status['can_upload'] and 'seo' in status['fields']
source=upload('source',ROOT/'build/Dayu-Portrait-1.2.0-source.zip','application/zip') source=upload('source',ROOT/'build/Dayu-Portrait-1.2.0-source.zip','application/zip')
card=upload('card',ROOT/'beatygril/beatygril/Wrapper Application/Resources/LauncherInfo.png','image/png') card=upload('card',ROOT/'FCP-BeautyGirl/FCP-BeautyGirl/Wrapper Application/Resources/LauncherInfo.png','image/png')
content=(ROOT/'releases/1.2.0/article.html').read_text().replace('{{source_url}}',html.escape(source['url'],quote=True)).replace('{{card_url}}',html.escape(card['url'],quote=True)) content=(ROOT/'releases/1.2.0/article.html').read_text().replace('{{source_url}}',html.escape(source['url'],quote=True)).replace('{{card_url}}',html.escape(card['url'],quote=True))
seo={ seo={
'title':{'enabled':True,'value':'大鱼人像美化 1.2.0|FCP / Motion 免费开源自动美颜插件'}, 'title':{'enabled':True,'value':'大鱼人像美化 1.2.0|FCP / Motion 免费开源自动美颜插件'},
+4 -4
查看文件
@@ -1,13 +1,13 @@
#!/bin/zsh #!/bin/zsh
set -euo pipefail set -euo pipefail
cd "${0:A:h:h}" cd "${0:A:h:h}"
output_dir=$(mktemp -d /tmp/paintfcp-host-tests.XXXXXX) output_dir=$(mktemp -d /tmp/fcp-beautygirl-host-tests.XXXXXX)
trap 'rm -rf "$output_dir"' EXIT trap 'rm -rf "$output_dir"' EXIT
plugin_dir="$PWD/beatygril/beatygril/Plugin" plugin_dir="$PWD/FCP-BeautyGirl/FCP-BeautyGirl/Plugin"
sdk_frameworks=/Library/Developer/SDKs/FxPlug.sdk/Library/Frameworks sdk_frameworks=/Library/Developer/SDKs/FxPlug.sdk/Library/Frameworks
runtime_frameworks=/Library/Developer/Frameworks runtime_frameworks=/Library/Developer/Frameworks
compiler_extra=() compiler_extra=()
if [[ "${PAINTFCP_HOST_ASAN:-0}" == 1 ]]; then if [[ "${FCP_BEAUTYGIRL_HOST_ASAN:-0}" == 1 ]]; then
compiler_extra=(-fsanitize=address -g) compiler_extra=(-fsanitize=address -g)
fi fi
xcrun clang "${compiler_extra[@]}" -fobjc-arc -fmodules -Wall -Wextra -Wno-unused-parameter \ xcrun clang "${compiler_extra[@]}" -fobjc-arc -fmodules -Wall -Wextra -Wno-unused-parameter \
@@ -16,7 +16,7 @@ xcrun clang "${compiler_extra[@]}" -fobjc-arc -fmodules -Wall -Wextra -Wno-unuse
-Wl,-rpath,"$runtime_frameworks" \ -Wl,-rpath,"$runtime_frameworks" \
"$plugin_dir/PGBeautyRenderer.m" "$plugin_dir/PGFaceProcessor.m" \ "$plugin_dir/PGBeautyRenderer.m" "$plugin_dir/PGFaceProcessor.m" \
"$plugin_dir/PGInspectorState.m" "$plugin_dir/PGInspectorView.m" \ "$plugin_dir/PGInspectorState.m" "$plugin_dir/PGInspectorView.m" \
"$plugin_dir/beatygrilPlugIn.m" tests/host_adapter_tests.m \ "$plugin_dir/FCPBeautyGirlPlugIn.m" tests/host_adapter_tests.m \
-framework Foundation -framework AppKit -framework CoreImage -framework CoreGraphics \ -framework Foundation -framework AppKit -framework CoreImage -framework CoreGraphics \
-framework CoreMedia -framework CoreVideo -framework IOSurface -framework Metal \ -framework CoreMedia -framework CoreVideo -framework IOSurface -framework Metal \
-framework Vision -framework ImageIO -framework FxPlug -framework PluginManager \ -framework Vision -framework ImageIO -framework FxPlug -framework PluginManager \
+4 -4
查看文件
@@ -1,11 +1,11 @@
#!/bin/zsh #!/bin/zsh
set -euo pipefail set -euo pipefail
cd "${0:A:h:h}" cd "${0:A:h:h}"
output_dir=$(mktemp -d /tmp/paintfcp-inspector-tests.XXXXXX) output_dir=$(mktemp -d /tmp/fcp-beautygirl-inspector-tests.XXXXXX)
trap 'rm -rf "$output_dir"' EXIT trap 'rm -rf "$output_dir"' EXIT
plugin_dir="$PWD/beatygril/beatygril/Plugin" plugin_dir="$PWD/FCP-BeautyGirl/FCP-BeautyGirl/Plugin"
compiler_extra=() compiler_extra=()
if [[ "${PAINTFCP_INSPECTOR_ASAN:-0}" == 1 ]]; then if [[ "${FCP_BEAUTYGIRL_INSPECTOR_ASAN:-0}" == 1 ]]; then
compiler_extra=(-fsanitize=address -g) compiler_extra=(-fsanitize=address -g)
fi fi
python3 scripts/inspector-template.py audit 'Templates/大鱼人像美化/大鱼人像美化.moef' \ python3 scripts/inspector-template.py audit 'Templates/大鱼人像美化/大鱼人像美化.moef' \
@@ -16,7 +16,7 @@ xcrun clang "${compiler_extra[@]}" -fobjc-arc -fmodules -Wall -Wextra -Wno-unuse
-Wl,-rpath,/Library/Developer/Frameworks \ -Wl,-rpath,/Library/Developer/Frameworks \
"$plugin_dir/PGBeautyRenderer.m" "$plugin_dir/PGFaceProcessor.m" \ "$plugin_dir/PGBeautyRenderer.m" "$plugin_dir/PGFaceProcessor.m" \
"$plugin_dir/PGInspectorState.m" "$plugin_dir/PGInspectorView.m" \ "$plugin_dir/PGInspectorState.m" "$plugin_dir/PGInspectorView.m" \
"$plugin_dir/beatygrilPlugIn.m" tests/inspector_tests.m \ "$plugin_dir/FCPBeautyGirlPlugIn.m" tests/inspector_tests.m \
-framework Foundation -framework AppKit -framework CoreImage -framework CoreGraphics \ -framework Foundation -framework AppKit -framework CoreImage -framework CoreGraphics \
-framework CoreMedia -framework CoreVideo -framework IOSurface -framework Metal \ -framework CoreMedia -framework CoreVideo -framework IOSurface -framework Metal \
-framework Vision -framework ImageIO -framework FxPlug -framework PluginManager \ -framework Vision -framework ImageIO -framework FxPlug -framework PluginManager \
+3 -3
查看文件
@@ -1,13 +1,13 @@
#!/bin/zsh #!/bin/zsh
set -euo pipefail set -euo pipefail
cd "${0:A:h:h}" cd "${0:A:h:h}"
output_dir=$(mktemp -d /tmp/paintfcp-osc-tests.XXXXXX) output_dir=$(mktemp -d /tmp/fcp-beautygirl-osc-tests.XXXXXX)
trap 'rm -rf "$output_dir"' EXIT trap 'rm -rf "$output_dir"' EXIT
plugin_dir="$PWD/beatygril/beatygril/Plugin" plugin_dir="$PWD/FCP-BeautyGirl/FCP-BeautyGirl/Plugin"
sdk_frameworks=/Library/Developer/SDKs/FxPlug.sdk/Library/Frameworks sdk_frameworks=/Library/Developer/SDKs/FxPlug.sdk/Library/Frameworks
runtime_frameworks=/Library/Developer/Frameworks runtime_frameworks=/Library/Developer/Frameworks
compiler_extra=() compiler_extra=()
if [[ "${PAINTFCP_OSC_ASAN:-0}" == 1 ]]; then if [[ "${FCP_BEAUTYGIRL_OSC_ASAN:-0}" == 1 ]]; then
compiler_extra=(-fsanitize=address -g) compiler_extra=(-fsanitize=address -g)
fi fi
xcrun clang "${compiler_extra[@]}" -fobjc-arc -fmodules -Wall -Wextra -Wno-unused-parameter \ xcrun clang "${compiler_extra[@]}" -fobjc-arc -fmodules -Wall -Wextra -Wno-unused-parameter \
+2 -2
查看文件
@@ -1,9 +1,9 @@
#!/bin/zsh #!/bin/zsh
set -euo pipefail set -euo pipefail
cd "${0:A:h:h}" cd "${0:A:h:h}"
output_dir=$(mktemp -d /tmp/paintfcp-tests.XXXXXX) output_dir=$(mktemp -d /tmp/fcp-beautygirl-tests.XXXXXX)
trap 'rm -rf "$output_dir"' EXIT trap 'rm -rf "$output_dir"' EXIT
plugin_dir="$PWD/beatygril/beatygril/Plugin" plugin_dir="$PWD/FCP-BeautyGirl/FCP-BeautyGirl/Plugin"
common=(-fobjc-arc -fmodules -Wall -Wextra -Wno-unused-parameter -DCI_SILENCE_GL_DEPRECATION -mmacosx-version-min=13.0 -I "$plugin_dir" -framework Foundation -framework CoreImage -framework CoreGraphics -framework CoreMedia -framework Metal -framework Vision -framework ImageIO) common=(-fobjc-arc -fmodules -Wall -Wextra -Wno-unused-parameter -DCI_SILENCE_GL_DEPRECATION -mmacosx-version-min=13.0 -I "$plugin_dir" -framework Foundation -framework CoreImage -framework CoreGraphics -framework CoreMedia -framework Metal -framework Vision -framework ImageIO)
xcrun clang "${common[@]}" "$plugin_dir/PGBeautyRenderer.m" tests/beauty_render_tests.m -o "$output_dir/beauty-tests" xcrun clang "${common[@]}" "$plugin_dir/PGBeautyRenderer.m" tests/beauty_render_tests.m -o "$output_dir/beauty-tests"
"$output_dir/beauty-tests" "$output_dir/beauty-tests"
+4 -3
查看文件
@@ -3,6 +3,7 @@
Only --publish performs writes. Credentials stay in memory and go only to Dayu. Only --publish performs writes. Credentials stay in memory and go only to Dayu.
""" """
import argparse, base64, hashlib, html, json, pathlib, ssl, subprocess, urllib.parse, urllib.request, uuid, zipfile import argparse, base64, hashlib, html, json, pathlib, ssl, subprocess, urllib.parse, urllib.request, uuid, zipfile
from product_identity import PRODUCT
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--version', required=True) parser.add_argument('--version', required=True)
@@ -49,8 +50,8 @@ if not args.publish:
raise SystemExit(0) raise SystemExit(0)
baseline = json.loads((work / 'article-before.json').read_text())['article'] baseline = json.loads((work / 'article-before.json').read_text())['article']
payload = json.loads((release / 'article-payload.json').read_text()) payload = json.loads((release / 'article-payload.json').read_text())
package = release / ('大鱼人像美化-' + args.version + '.pkg') package = release / (PRODUCT['name'] + '-' + args.version + '.pkg')
source = root / 'build' / ('Dayu-Portrait-' + args.version + '-source.zip') source = root / 'build' / (PRODUCT['name'] + '-' + args.version + '-source.zip')
with zipfile.ZipFile(source) as z: with zipfile.ZipFile(source) as z:
assert z.testzip() is None and any(n.endswith('/Wrapper Application/AppDelegate.m') for n in z.namelist()) assert z.testzip() is None and any(n.endswith('/Wrapper Application/AppDelegate.m') for n in z.namelist())
assert not any(n.endswith(('.app', '.pkg', '.p12', '.key', '.env')) for n in z.namelist()) assert not any(n.endswith(('.app', '.pkg', '.p12', '.key', '.env')) for n in z.namelist())
@@ -77,7 +78,7 @@ assert '{{' not in payload['content']
if not state.get('response'): if not state.get('response'):
boundary = 'DayuRelease' + state['idempotencyKey'].replace('-', '') boundary = 'DayuRelease' + state['idempotencyKey'].replace('-', '')
parts = [] parts = []
for name, data, filename, mime in [('payload', json.dumps(payload, ensure_ascii=False).encode(), None, 'application/json'), ('package', package.read_bytes(), 'Dayu-Portrait-' + args.version + '.pkg', 'application/octet-stream')]: for name, data, filename, mime in [('payload', json.dumps(payload, ensure_ascii=False).encode(), None, 'application/json'), ('package', package.read_bytes(), package.name, 'application/octet-stream')]:
head = '--' + boundary + '\r\nContent-Disposition: form-data; name="' + name + '"' head = '--' + boundary + '\r\nContent-Disposition: form-data; name="' + name + '"'
if filename: if filename:
head += '; filename="' + filename + '"' head += '; filename="' + filename + '"'
+9 -5
查看文件
@@ -2,15 +2,16 @@
"""Verify an expanded release payload and run template-only update/rollback in isolation.""" """Verify an expanded release payload and run template-only update/rollback in isolation."""
from pathlib import Path from pathlib import Path
import argparse,hashlib,json,os,plistlib,shutil,subprocess,sys import argparse,hashlib,json,os,plistlib,shutil,subprocess,sys
from product_identity import PRODUCT
root=Path(__file__).resolve().parent.parent root=Path(__file__).resolve().parent.parent
parser=argparse.ArgumentParser(description=__doc__) parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--version',default='1.2.0') parser.add_argument('--version',default=PRODUCT['version'])
parser.add_argument('--build',default='14') parser.add_argument('--build',default=PRODUCT['build'])
parser.add_argument('--expanded',default='build/pkg-expanded') parser.add_argument('--expanded',default='build/pkg-expanded')
parser.add_argument('--fixture',default='build/pkg-isolation') parser.add_argument('--fixture',default='build/pkg-isolation')
args=parser.parse_args() args=parser.parse_args()
expanded=root/args.expanded/'Payload.pkg';payload=expanded/'Payload' expanded=root/args.expanded/'Payload.pkg';payload=expanded/'Payload'
formal=Path('/Library/Plug-Ins/FxPlug/beatygril.app');packed=payload/'Library/Plug-Ins/FxPlug/beatygril.app' formal=Path('/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app');packed=payload/'Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app'
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest() sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
def files(p): def files(p):
return {str(x.relative_to(p)):('symlink:'+os.readlink(x) if x.is_symlink() else sha(x)) for x in p.rglob('*') if x.is_file() or x.is_symlink()} return {str(x.relative_to(p)):('symlink:'+os.readlink(x) if x.is_symlink() else sha(x)) for x in p.rglob('*') if x.is_file() or x.is_symlink()}
@@ -33,7 +34,10 @@ base=root/args.fixture;base.mkdir(exist_ok=False)
volume=base/'volume';home=base/'user';home.mkdir() volume=base/'volume';home=base/'user';home.mkdir()
start=post.index('CURRENT_ACTIVE=0') start=post.index('CURRENT_ACTIVE=0')
isolated='#!/bin/zsh\nset -eu\nTARGET_VOLUME="'+str(volume)+'"\nCONSOLE_USER="'+os.getlogin()+'"\nCONSOLE_UID="'+str(os.getuid())+'"\nCONSOLE_GROUP="staff"\nUSER_HOME="'+str(home)+'"\n'+post[start:] isolated='#!/bin/zsh\nset -eu\nTARGET_VOLUME="'+str(volume)+'"\nCONSOLE_USER="'+os.getlogin()+'"\nCONSOLE_UID="'+str(os.getuid())+'"\nCONSOLE_GROUP="staff"\nUSER_HOME="'+str(home)+'"\n'+post[start:]
isolated=isolated[:isolated.index('fx_verify_app "${TARGET_VOLUME%/}/Library/Plug-Ins/FxPlug/beatygril.app"')]+'exit 0\n' stop = isolated.find('# FCP-BeautyGirl identity migration.')
if stop < 0:
stop = isolated.index('fx_verify_app "${TARGET_VOLUME%/}/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app"')
isolated=isolated[:stop]+'exit 0\n'
isolated=isolated.replace('/usr/sbin/chown -R','/usr/bin/true') isolated=isolated.replace('/usr/sbin/chown -R','/usr/bin/true')
new_copy=next(l for l in isolated.splitlines() if l.startswith('/usr/bin/ditto "${TARGET_VOLUME%/}')) new_copy=next(l for l in isolated.splitlines() if l.startswith('/usr/bin/ditto "${TARGET_VOLUME%/}'))
def refill(): def refill():
@@ -66,7 +70,7 @@ assert files(final)==original
assert all((final/n).stat().st_flags & 2 for n in ['large.png','small.png']) assert all((final/n).stat().st_flags & 2 for n in ['large.png','small.png'])
backups=list((home/'Library/Application Support/PKGForge/Template Backups').rglob('.locked-paths')) backups=list((home/'Library/Application Support/PKGForge/Template Backups').rglob('.locked-paths'))
assert backups and all('/Movies/' not in str(x) for x in backups) assert backups and all('/Movies/' not in str(x) for x in backups)
package=root/('releases/'+args.version+'/大鱼人像美化-'+args.version+'.pkg') package=root/('releases/'+args.version+'/'+PRODUCT['name']+'-'+args.version+'.pkg')
info=plistlib.loads((packed/'Contents/Info.plist').read_bytes()) info=plistlib.loads((packed/'Contents/Info.plist').read_bytes())
assert info['CFBundleShortVersionString']==args.version and info['CFBundleVersion']==args.build assert info['CFBundleShortVersionString']==args.version and info['CFBundleVersion']==args.build
report={'package':str(package.relative_to(root)),'bytes':package.stat().st_size,'sha256':sha(package),'version':args.version,'build':args.build,'app_files_compared':len(files(formal)),'app_byte_and_symlink_equality':True,'template_files':{n:sha(template/n) for n in runtime},'locked_relative_paths':['大鱼人像美化/large.png','大鱼人像美化/small.png'],'script_sha256':{'preinstall':sha(expanded/'Scripts/preinstall'),'postinstall':sha(expanded/'Scripts/postinstall')},'isolated_script_tests':['fresh install','replace old locked thumbnail','partial copy failure restores old bytes and locks'],'isolation_changes':['Console identity/home redirected to task fixture','chown replaced with true','FxPlug verification skipped; formal app signature and discovery verified separately'],'real_installer_execution':False,'app_and_template_installed':'APP installed through signed delivery workflow; formal template files matched the specified installed category, not changed by running this PKG','fonts':'No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed.'} report={'package':str(package.relative_to(root)),'bytes':package.stat().st_size,'sha256':sha(package),'version':args.version,'build':args.build,'app_files_compared':len(files(formal)),'app_byte_and_symlink_equality':True,'template_files':{n:sha(template/n) for n in runtime},'locked_relative_paths':['大鱼人像美化/large.png','大鱼人像美化/small.png'],'script_sha256':{'preinstall':sha(expanded/'Scripts/preinstall'),'postinstall':sha(expanded/'Scripts/postinstall')},'isolated_script_tests':['fresh install','replace old locked thumbnail','partial copy failure restores old bytes and locks'],'isolation_changes':['Console identity/home redirected to task fixture','chown replaced with true','FxPlug verification skipped; formal app signature and discovery verified separately'],'real_installer_execution':False,'app_and_template_installed':'APP installed through signed delivery workflow; formal template files matched the specified installed category, not changed by running this PKG','fonts':'No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed.'}
+11 -11
查看文件
@@ -5,7 +5,7 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
#import <CoreVideo/CoreVideo.h> #import <CoreVideo/CoreVideo.h>
#import <ImageIO/ImageIO.h> #import <ImageIO/ImageIO.h>
#import "beatygrilPlugIn.h" #import "FCPBeautyGirlPlugIn.h"
#import "PGParameterIDs.h" #import "PGParameterIDs.h"
#import "PGFaceProcessor.h" #import "PGFaceProcessor.h"
#import "PGBeautyRenderer.h" #import "PGBeautyRenderer.h"
@@ -209,19 +209,19 @@ static NSData *ExpectedCrop(PGHostTile *source, NSUInteger x, NSUInteger y, NSUI
} }
return result; return result;
} }
static NSData *Snapshot(beatygrilPlugIn *plugin, CMTime time) { static NSData *Snapshot(FCPBeautyGirlPlugIn *plugin, CMTime time) {
NSData *state = nil; NSError *error = nil; NSData *state = nil; NSError *error = nil;
Check([plugin pluginState:&state atTime:time quality:kFxQuality_HIGH error:&error] && state.length > 0 && !error, @"plugin snapshot serializes through host parameter API"); Check([plugin pluginState:&state atTime:time quality:kFxQuality_HIGH error:&error] && state.length > 0 && !error, @"plugin snapshot serializes through host parameter API");
return state; return state;
} }
static BOOL Render(beatygrilPlugIn *plugin, PGHostTile *destination, NSArray *sources, NSData *state, CMTime time, NSError **error, BOOL *escaped) { static BOOL Render(FCPBeautyGirlPlugIn *plugin, PGHostTile *destination, NSArray *sources, NSData *state, CMTime time, NSError **error, BOOL *escaped) {
@try { return [plugin renderDestinationImage:destination sourceImages:sources pluginState:state atTime:time error:error]; } @try { return [plugin renderDestinationImage:destination sourceImages:sources pluginState:state atTime:time error:error]; }
@catch (NSException *exception) { @catch (NSException *exception) {
if (escaped) *escaped = YES; if (escaped) *escaped = YES;
fprintf(stderr, "EXCEPTION: %s\n", exception.reason.UTF8String); return NO; fprintf(stderr, "EXCEPTION: %s\n", exception.reason.UTF8String); return NO;
} }
} }
static void RejectState(beatygrilPlugIn *plugin, PGHostTile *destination, PGHostTile *source, NSData *state, NSString *description) { static void RejectState(FCPBeautyGirlPlugIn *plugin, PGHostTile *destination, PGHostTile *source, NSData *state, NSString *description) {
NSError *error = nil; BOOL escaped = NO; NSError *error = nil; BOOL escaped = NO;
BOOL rendered = Render(plugin, destination, @[source], state, kCMTimeZero, &error, &escaped); BOOL rendered = Render(plugin, destination, @[source], state, kCMTimeZero, &error, &escaped);
Check(!rendered && !escaped && error != nil, description); Check(!rendered && !escaped && error != nil, description);
@@ -353,7 +353,7 @@ static void PortraitAnatomyTests(NSString *fixture, CIImage *portrait) {
NSData *originBaseline = nil; NSData *originBaseline = nil;
for (NSUInteger sourceTop = 0; sourceTop < 2; sourceTop++) for (NSUInteger destinationTop = 0; destinationTop < 2; destinationTop++) { for (NSUInteger sourceTop = 0; sourceTop < 2; sourceTop++) for (NSUInteger destinationTop = 0; destinationTop < 2; destinationTop++) {
@autoreleasepool { @autoreleasepool {
PGHostAPI *api = [PGHostAPI new]; beatygrilPlugIn *plugin = [[beatygrilPlugIn alloc] initWithAPIManager:api]; PGHostAPI *api = [PGHostAPI new]; FCPBeautyGirlPlugIn *plugin = [[FCPBeautyGirlPlugIn alloc] initWithAPIManager:api];
Check([plugin addParametersWithError:nil], @"anatomy case creates the real plugin parameters"); Check([plugin addParametersWithError:nil], @"anatomy case creates the real plugin parameters");
if (effect) api.values[@(controls[effect])] = @(values[effect]); if (effect) api.values[@(controls[effect])] = @(values[effect]);
PGHostTile *input = Tile(width, height, 37, -21, sourceTop ? kFxImageOrigin_TOP_LEFT : kFxImageOrigin_BOTTOM_LEFT); PGHostTile *input = Tile(width, height, 37, -21, sourceTop ? kFxImageOrigin_TOP_LEFT : kFxImageOrigin_BOTTOM_LEFT);
@@ -406,7 +406,7 @@ static void TrackingCoordinateTests(NSDictionary *archive, NSDictionary *hostVal
values[@(PGTarget)] = @2; values[@(PGTrackEnabled)] = @YES; values[@(PGBigEye)] = @1; values[@(PGChin)] = @1; values[@(PGTarget)] = @2; values[@(PGTrackEnabled)] = @YES; values[@(PGBigEye)] = @1; values[@(PGChin)] = @1;
values[@(PGTrackData3)] = legacyString; values[@(PGTrackData3)] = legacyString;
PGHostAPI *legacyAPI = [PGHostAPI new]; legacyAPI.hostTime = time; PGHostAPI *legacyAPI = [PGHostAPI new]; legacyAPI.hostTime = time;
beatygrilPlugIn *legacy = [[beatygrilPlugIn alloc] initWithAPIManager:legacyAPI]; [legacy addParametersWithError:nil]; legacyAPI.values = [values mutableCopy]; FCPBeautyGirlPlugIn *legacy = [[FCPBeautyGirlPlugIn alloc] initWithAPIManager:legacyAPI]; [legacy addParametersWithError:nil]; legacyAPI.values = [values mutableCopy];
PGHostTile *output = Tile(512,512,0,0,kFxImageOrigin_TOP_LEFT); PGHostTile *output = Tile(512,512,0,0,kFxImageOrigin_TOP_LEFT);
Check(Render(legacy, output, @[source], Snapshot(legacy,time), time, nil, NULL), @"unmarked old coordinate archive renders through the real adapter"); Check(Render(legacy, output, @[source], Snapshot(legacy,time), time, nil, NULL), @"unmarked old coordinate archive renders through the real adapter");
NSData *legacyBytes = SurfaceBytes(output); NSData *legacyBytes = SurfaceBytes(output);
@@ -420,7 +420,7 @@ static void TrackingCoordinateTests(NSDictionary *archive, NSDictionary *hostVal
forged[@"hostCoordinateSpace"] = @"iosurface-ci-y-up-v1"; forged[@"hostCoordinateSpace"] = @"iosurface-ci-y-up-v1";
NSData *trustedTrack = PlistState(forged); NSData *trustedTrack = PlistState(forged);
PGHostAPI *trustedAPI = [PGHostAPI new]; trustedAPI.hostTime = time; PGHostAPI *trustedAPI = [PGHostAPI new]; trustedAPI.hostTime = time;
beatygrilPlugIn *trusted = [[beatygrilPlugIn alloc] initWithAPIManager:trustedAPI]; [trusted addParametersWithError:nil]; FCPBeautyGirlPlugIn *trusted = [[FCPBeautyGirlPlugIn alloc] initWithAPIManager:trustedAPI]; [trusted addParametersWithError:nil];
trustedAPI.values = [values mutableCopy]; trustedAPI.values[@(PGTrackData3)] = [trustedTrack base64EncodedStringWithOptions:0]; trustedAPI.values = [values mutableCopy]; trustedAPI.values[@(PGTrackData3)] = [trustedTrack base64EncodedStringWithOptions:0];
Check(Render(trusted, output, @[source], Snapshot(trusted,time), time, nil, NULL), @"fresh plugin accepts a snapshot with marked legacy analysis data"); Check(Render(trusted, output, @[source], Snapshot(trusted,time), time, nil, NULL), @"fresh plugin accepts a snapshot with marked legacy analysis data");
NSData *trustedBytes = SurfaceBytes(output); NSData *trustedBytes = SurfaceBytes(output);
@@ -465,7 +465,7 @@ static BOOL Preview(PGHostTile *before, PGHostTile *after, NSString *path) {
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
setbuf(stdout, NULL); setbuf(stdout, NULL);
@autoreleasepool { @autoreleasepool {
PGHostAPI *api = [PGHostAPI new]; beatygrilPlugIn *plugin = [[beatygrilPlugIn alloc] initWithAPIManager:api]; PGHostAPI *api = [PGHostAPI new]; FCPBeautyGirlPlugIn *plugin = [[FCPBeautyGirlPlugIn alloc] initWithAPIManager:api];
NSError *error = nil; NSError *error = nil;
Check([plugin addParametersWithError:&error] && !error, @"host creates complete parameter set"); Check([plugin addParametersWithError:&error] && !error, @"host creates complete parameter set");
UInt32 identifiers[] = {PGAmount,PGBrightness,PGRadius,PGSharpness,PGMix,PGThreshold,PGSoftness,PGEdgeProtect,PGShowMask,PGMidtone,PGHue,PGSaturation,PGHighPass,PGThin,PGFaceBoxes,PGSingleFace,PGSelection,PGShort,PGNarrow,PGChin,PGVFace,PGJaw,PGCheekbone,PGSmallHead,PGSmallHeadRange,PGFeatureProtect,PGTeeth,PGEyeBright,PGBigEye,PGTrackBoxes,PGFastMulti,PGJumpGuard,PGEvenTone,PGTonePreset,PGInvertMask,PGDebugChannel,PGTrackEnabled,PGTarget,PGAnalyzeForward,PGAnalyzeBackward,PGClearTrack,PGStatus,PGTrackData1,PGTrackData2,PGTrackData3,PGSmoothingEnabled,PGColorEnabled,PGShapeEnabled,PGDetailEnabled,PGInspectorPanel}; UInt32 identifiers[] = {PGAmount,PGBrightness,PGRadius,PGSharpness,PGMix,PGThreshold,PGSoftness,PGEdgeProtect,PGShowMask,PGMidtone,PGHue,PGSaturation,PGHighPass,PGThin,PGFaceBoxes,PGSingleFace,PGSelection,PGShort,PGNarrow,PGChin,PGVFace,PGJaw,PGCheekbone,PGSmallHead,PGSmallHeadRange,PGFeatureProtect,PGTeeth,PGEyeBright,PGBigEye,PGTrackBoxes,PGFastMulti,PGJumpGuard,PGEvenTone,PGTonePreset,PGInvertMask,PGDebugChannel,PGTrackEnabled,PGTarget,PGAnalyzeForward,PGAnalyzeBackward,PGClearTrack,PGStatus,PGTrackData1,PGTrackData2,PGTrackData3,PGSmoothingEnabled,PGColorEnabled,PGShapeEnabled,PGDetailEnabled,PGInspectorPanel};
@@ -589,7 +589,7 @@ int main(int argc, const char *argv[]) {
TrackingCoordinateTests(trackingArchive,api.values,portraitSource,portrait,api.hostTime); TrackingCoordinateTests(trackingArchive,api.values,portraitSource,portrait,api.hostTime);
Check([api.values[@(PGTrackEnabled)] boolValue] && CMTimeCompare(api.lastSetBoolTime, api.hostTime) == 0, @"analysis enables saved target at host seed time"); Check([api.values[@(PGTrackEnabled)] boolValue] && CMTimeCompare(api.lastSetBoolTime, api.hostTime) == 0, @"analysis enables saved target at host seed time");
NSData *trackedState = Snapshot(plugin, api.hostTime); NSData *trackedState = Snapshot(plugin, api.hostTime);
beatygrilPlugIn *restoredPlugin = [[beatygrilPlugIn alloc] initWithAPIManager:api]; FCPBeautyGirlPlugIn *restoredPlugin = [[FCPBeautyGirlPlugIn alloc] initWithAPIManager:api];
Check(Render(restoredPlugin, portraitOutput, @[portraitSource], trackedState, api.hostTime, &error, NULL), @"fresh plugin instance uses automatic follow despite serialized legacy analysis settings"); Check(Render(restoredPlugin, portraitOutput, @[portraitSource], trackedState, api.hostTime, &error, NULL), @"fresh plugin instance uses automatic follow despite serialized legacy analysis settings");
[plugin analyzeBackward]; [plugin analyzeBackward];
Check(api.backwardRequests == 1, @"backward analyze button calls host API"); Check(api.backwardRequests == 1, @"backward analyze button calls host API");
@@ -598,7 +598,7 @@ int main(int argc, const char *argv[]) {
[plugin setupAnalysisForTimeRange:desired frameDuration:CMTimeMake(1, 24) error:&error]; [plugin cleanupAnalysis:&error]; [plugin setupAnalysisForTimeRange:desired frameDuration:CMTimeMake(1, 24) error:&error]; [plugin cleanupAnalysis:&error];
[plugin clearTracking]; Check([api.values[@(PGTrackData3)] length] == 0, @"clear button uses current host target"); [plugin clearTracking]; Check([api.values[@(PGTrackData3)] length] == 0, @"clear button uses current host target");
PGHostAPI *writeFailureAPI = [PGHostAPI new]; PGHostAPI *writeFailureAPI = [PGHostAPI new];
beatygrilPlugIn *writeFailurePlugin = [[beatygrilPlugIn alloc] initWithAPIManager:writeFailureAPI]; FCPBeautyGirlPlugIn *writeFailurePlugin = [[FCPBeautyGirlPlugIn alloc] initWithAPIManager:writeFailureAPI];
[writeFailurePlugin addParametersWithError:&error]; [writeFailurePlugin analyzeForward]; [writeFailurePlugin addParametersWithError:&error]; [writeFailurePlugin analyzeForward];
[writeFailurePlugin setupAnalysisForTimeRange:clip frameDuration:CMTimeMake(1, 24) error:&error]; [writeFailurePlugin setupAnalysisForTimeRange:clip frameDuration:CMTimeMake(1, 24) error:&error];
[writeFailurePlugin analyzeFrame:portraitSource atTime:writeFailureAPI.hostTime error:&error]; [writeFailurePlugin analyzeFrame:portraitSource atTime:writeFailureAPI.hostTime error:&error];
@@ -608,7 +608,7 @@ int main(int argc, const char *argv[]) {
[writeFailurePlugin analyzeForward]; [writeFailurePlugin analyzeForward];
Check(writeFailureAPI.forwardRequests == 2, @"persistence failure releases analysis busy state for retry"); Check(writeFailureAPI.forwardRequests == 2, @"persistence failure releases analysis busy state for retry");
PGHostAPI *unavailable = [PGHostAPI new]; [unavailable.disabledAPIs addObject:@"FxParameterCreationAPI_v5"]; PGHostAPI *unavailable = [PGHostAPI new]; [unavailable.disabledAPIs addObject:@"FxParameterCreationAPI_v5"];
beatygrilPlugIn *missingPlugin = [[beatygrilPlugIn alloc] initWithAPIManager:unavailable]; FCPBeautyGirlPlugIn *missingPlugin = [[FCPBeautyGirlPlugIn alloc] initWithAPIManager:unavailable];
error = nil; Check(![missingPlugin addParametersWithError:&error] && error != nil, @"missing host creation API reports error"); error = nil; Check(![missingPlugin addParametersWithError:&error] && error != nil, @"missing host creation API reports error");
[unavailable.disabledAPIs removeAllObjects]; unavailable.rejectedParameter = PGThin; [unavailable.disabledAPIs removeAllObjects]; unavailable.rejectedParameter = PGThin;
error = nil; Check(![missingPlugin addParametersWithError:&error] && error != nil, @"host rejecting one control fails complete parameter creation"); error = nil; Check(![missingPlugin addParametersWithError:&error] && error != nil, @"host rejecting one control fails complete parameter creation");
+91
查看文件
@@ -0,0 +1,91 @@
import importlib.util, json, pathlib, plistlib, subprocess, tempfile, unittest
from unittest.mock import patch
ROOT = pathlib.Path(__file__).resolve().parent.parent
spec = importlib.util.spec_from_file_location('product_identity', ROOT / 'scripts/product_identity.py')
identity = importlib.util.module_from_spec(spec)
spec.loader.exec_module(identity)
class IdentityMigrationTests(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory(prefix='beautygirl-identity-test.')
self.volume = pathlib.Path(self.tmp.name)
self.legacy = identity.PRODUCT['legacyProducts'][0]
self.old = self.volume / pathlib.Path(self.legacy['installationPath']).relative_to('/')
(self.old / 'Contents/PlugIns' / self.legacy['pluginName'] / 'Contents').mkdir(parents=True)
(self.old / 'Contents/Info.plist').write_bytes(plistlib.dumps({'CFBundleIdentifier': self.legacy['bundleIdentifier']}))
(self.old / 'Contents/PlugIns' / self.legacy['pluginName'] / 'Contents/Info.plist').write_bytes(plistlib.dumps({'ProPlugPlugInList': [{'uuid': identity.PRODUCT['filterUUID']}]}))
self.signature = patch.object(identity.subprocess, 'run', return_value=subprocess.CompletedProcess([], 0, '', 'TeamIdentifier=B3W25FX5H5\n'))
self.signature.start()
self.migration = identity.LegacyMigration(self.volume / 'backups', volume=self.volume)
def tearDown(self):
self.signature.stop()
self.tmp.cleanup()
def test_success_removes_only_validated_old_product(self):
original = (self.old / 'Contents/Info.plist').read_bytes()
unrelated = self.old.parent / 'Unrelated.app'
unrelated.mkdir()
calls = []
self.migration.relocate(calls.append)
self.assertFalse(self.old.exists())
self.assertEqual(len(calls), 1)
self.assertEqual((self.migration.moved[0][2] / 'Contents/Info.plist').read_bytes(), original)
self.assertEqual(len(self.migration.cleanup()), 1)
self.assertTrue(unrelated.exists())
def test_failed_new_install_restores_old_bytes_and_registration(self):
original = (self.old / 'Contents/Info.plist').read_bytes()
self.migration.relocate(lambda p: None)
calls = []
self.migration.rollback(calls.append)
self.assertEqual((self.old / 'Contents/Info.plist').read_bytes(), original)
self.assertEqual(calls, [self.old / 'Contents/PlugIns' / self.legacy['pluginName']])
def test_wrong_bundle_id_is_never_moved(self):
(self.old / 'Contents/Info.plist').write_bytes(plistlib.dumps({'CFBundleIdentifier': 'com.unrelated.product'}))
with self.assertRaisesRegex(RuntimeError, 'identity mismatch'):
self.migration.relocate(lambda p: self.fail('Must not deregister another product'))
self.assertTrue(self.old.exists())
def test_wrong_filter_uuid_is_never_moved(self):
(self.old / 'Contents/PlugIns' / self.legacy['pluginName'] / 'Contents/Info.plist').write_bytes(plistlib.dumps({'ProPlugPlugInList': []}))
with self.assertRaisesRegex(RuntimeError, 'filter UUID'):
self.migration.relocate(lambda p: self.fail('Must not deregister another filter'))
self.assertTrue(self.old.exists())
def test_invalid_signature_keeps_original(self):
with patch.object(identity.subprocess, 'run', side_effect=subprocess.CalledProcessError(1, 'codesign')):
with self.assertRaises(subprocess.CalledProcessError):
self.migration.relocate(lambda p: self.fail('Unverified APP must remain'))
self.assertTrue(self.old.exists())
def test_existing_backup_cannot_be_overwritten(self):
backup = self.volume / 'backups' / ('legacy-' + self.legacy['name'] + '.app')
backup.mkdir(parents=True)
with self.assertRaisesRegex(RuntimeError, 'already exists'):
self.migration.relocate(lambda p: self.fail('Recovery copy must be preserved'))
self.assertTrue(self.old.exists())
def test_failed_deregistration_keeps_old_installation(self):
def unavailable(path):
raise RuntimeError('registry unavailable')
with self.assertRaisesRegex(RuntimeError, 'registry unavailable'):
self.migration.relocate(unavailable)
self.assertTrue(self.old.exists())
def test_project_and_legacy_template_share_stable_filter_identity(self):
p = identity.PRODUCT
pbx = (ROOT / p['xcodeProject'] / 'project.pbxproj').read_text()
self.assertEqual(pbx.count('PRODUCT_BUNDLE_IDENTIFIER = ' + p['bundleIdentifier'] + ';'), 2)
self.assertEqual(pbx.count('PRODUCT_BUNDLE_IDENTIFIER = ' + p['pluginBundleIdentifier'] + ';'), 2)
self.assertNotIn('beatygril', pbx)
plugin = plistlib.loads((ROOT / p['sourceDirectory'] / 'Plugin/Info.plist').read_bytes())
self.assertEqual(plugin['ProPlugPlugInList'][0]['className'], p['pluginClass'])
self.assertEqual(plugin['ProPlugPlugInList'][0]['uuid'], p['filterUUID'])
self.assertEqual(plugin['CFBundleShortVersionString'], p['version'])
self.assertIn('pluginUUID="' + p['filterUUID'] + '"', (ROOT / 'Templates/大鱼人像美化/大鱼人像美化.moef').read_text())
if __name__ == '__main__':
unittest.main()
+8 -8
查看文件
@@ -56,7 +56,7 @@ static PGInspectorState *State(NSDictionary *values,NSSet *disabled) {
return [PGInspectorState stateWithValues:values disabledParameters:disabled?:[NSSet set] hasEdits:YES]; return [PGInspectorState stateWithValues:values disabledParameters:disabled?:[NSSet set] hasEdits:YES];
} }
static void RegistrationTests(void) { static void RegistrationTests(void) {
PGHostAPI *api=[PGHostAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil]; PGHostAPI *api=[PGHostAPI new];FCPBeautyGirlPlugIn *plugin=[[FCPBeautyGirlPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
NSUInteger visible=0;for(NSNumber *key in api.definitions){NSDictionary *d=api.definitions[key];if(!([d[@"flags"]unsignedIntValue]&kFxParameterFlag_HIDDEN)){visible++;Check(key.unsignedIntValue==PGInspectorPanel,@"only the custom panel is visible in the native parameter list");}} NSUInteger visible=0;for(NSNumber *key in api.definitions){NSDictionary *d=api.definitions[key];if(!([d[@"flags"]unsignedIntValue]&kFxParameterFlag_HIDDEN)){visible++;Check(key.unsignedIntValue==PGInspectorPanel,@"only the custom panel is visible in the native parameter list");}}
Check(visible==1,@"all duplicate standard controls and manual-analysis groups are hidden"); Check(visible==1,@"all duplicate standard controls and manual-analysis groups are hidden");
FxParameterFlags flags=[api.definitions[@(PGInspectorPanel)][@"flags"]unsignedIntValue]; FxParameterFlags flags=[api.definitions[@(PGInspectorPanel)][@"flags"]unsignedIntValue];
@@ -136,7 +136,7 @@ static void ModelTests(void) {
Check(s.faceChin==0 && s.faceBigEye==0 && s.skinBrightness==0 && s.skinTonePreset==0 && s.midtoneDetail==0 && s.highPassDetail==0 && s.showTrackBox==0,@"card eye switches bypass the complete associated effect group"); Check(s.faceChin==0 && s.faceBigEye==0 && s.skinBrightness==0 && s.skinTonePreset==0 && s.midtoneDetail==0 && s.highPassDetail==0 && s.showTrackBox==0,@"card eye switches bypass the complete associated effect group");
} }
static void ControllerTests(void) { static void ControllerTests(void) {
PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil]; PGInspectorTestAPI *api=[PGInspectorTestAPI new];FCPBeautyGirlPlugIn *plugin=[[FCPBeautyGirlPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.values[@(PGMidtone)]=@.5; api.values[@(PGMidtone)]=@.5;
PGInspectorController *c=[[PGInspectorController alloc]initWithAPIManager:api];[c refresh]; PGInspectorController *c=[[PGInspectorController alloc]initWithAPIManager:api];[c refresh];
Check(c.available && Near([c.state valueForParameter:PGMidtone],.5) && !c.state.hasEdits,@"initial UI reads the current legacy/template values instead of replacing them"); Check(c.available && Near([c.state valueForParameter:PGMidtone],.5) && !c.state.hasEdits,@"initial UI reads the current legacy/template values instead of replacing them");
@@ -169,7 +169,7 @@ static void ControllerTests(void) {
[c setValue:.1 forParameter:PGBrightness];Check(Near([c.state valueForParameter:PGChin],-.8),@"new-time edits preserve the other controls from that time instead of a stale prior frame"); [c setValue:.1 forParameter:PGBrightness];Check(Near([c.state valueForParameter:PGChin],-.8),@"new-time edits preserve the other controls from that time instead of a stale prior frame");
api.values=[api.undoValues mutableCopy];[c documentDidChange]; api.values=[api.undoValues mutableCopy];[c documentDidChange];
Check(Near([c.state valueForParameter:PGBrightness],[seekValues[@(PGBrightness)]doubleValue]),@"a host undo notification refreshes same-time state immediately without a timed wait"); Check(Near([c.state valueForParameter:PGBrightness],[seekValues[@(PGBrightness)]doubleValue]),@"a host undo notification refreshes same-time state immediately without a timed wait");
PGHostAPI *legacy=[PGHostAPI new];beatygrilPlugIn *legacyPlugin=[[beatygrilPlugIn alloc]initWithAPIManager:legacy];[legacyPlugin addParametersWithError:nil]; PGHostAPI *legacy=[PGHostAPI new];FCPBeautyGirlPlugIn *legacyPlugin=[[FCPBeautyGirlPlugIn alloc]initWithAPIManager:legacy];[legacyPlugin addParametersWithError:nil];
legacy.values[@(PGDetailEnabled)]=@NO;legacy.values[@(PGHighPass)]=@.6;legacy.values[@(PGSharpness)]=@.4; legacy.values[@(PGDetailEnabled)]=@NO;legacy.values[@(PGHighPass)]=@.6;legacy.values[@(PGSharpness)]=@.4;
PGInspectorController *imported=[[PGInspectorController alloc]initWithAPIManager:legacy];[imported refresh];[imported setValue:.3 forParameter:PGBrightness]; PGInspectorController *imported=[[PGInspectorController alloc]initWithAPIManager:legacy];[imported refresh];[imported setValue:.3 forParameter:PGBrightness];
PGBeautySettings migrated=PGSettingsWithInspectorState(PGBeautyDefaults(),imported.state); PGBeautySettings migrated=PGSettingsWithInspectorState(PGBeautyDefaults(),imported.state);
@@ -185,7 +185,7 @@ static void ControllerTests(void) {
Check(!offline.available && ![offline setValue:.2 forParameter:PGChin],@"missing host actions disable editing instead of unsafe parameter access"); Check(!offline.available && ![offline setValue:.2 forParameter:PGChin],@"missing host actions disable editing instead of unsafe parameter access");
} }
static void ViewInteractionTests(void) { static void ViewInteractionTests(void) {
PGHostAPI *api=[PGHostAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil]; PGHostAPI *api=[PGHostAPI new];FCPBeautyGirlPlugIn *plugin=[[FCPBeautyGirlPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost]; PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
NSSlider *chin=(NSSlider *)FindControl(view,NSSlider.class,@"下巴");Check(chin!=nil && chin.enabled,@"custom view exposes an accessible native chin slider"); NSSlider *chin=(NSSlider *)FindControl(view,NSSlider.class,@"下巴");Check(chin!=nil && chin.enabled,@"custom view exposes an accessible native chin slider");
chin.doubleValue=-.75;Fire(chin);PGInspectorState *s=api.values[@(PGInspectorPanel)]; chin.doubleValue=-.75;Fire(chin);PGInspectorState *s=api.values[@(PGInspectorPanel)];
@@ -238,7 +238,7 @@ static void ViewInteractionTests(void) {
} }
} }
static void BeautyControlInteractionTests(void) { static void BeautyControlInteractionTests(void) {
PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil]; PGInspectorTestAPI *api=[PGInspectorTestAPI new];FCPBeautyGirlPlugIn *plugin=[[FCPBeautyGirlPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.values[@(PGFeatureProtectionAmount)]=@.37;api.values[@(PGHighPass)]=@.63;api.values[@(PGHue)]=@12;api.values[@(PGBrightness)]=@.3; api.values[@(PGFeatureProtectionAmount)]=@.37;api.values[@(PGHighPass)]=@.63;api.values[@(PGHue)]=@12;api.values[@(PGBrightness)]=@.3;
PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost]; PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
Check(Near([view.controller.state valueForParameter:PGFeatureProtectionAmount],.37) && !view.controller.state.hasEdits,@"an untouched inspector preserves native fractional protection when the legacy boolean is enabled"); Check(Near([view.controller.state valueForParameter:PGFeatureProtectionAmount],.37) && !view.controller.state.hasEdits,@"an untouched inspector preserves native fractional protection when the legacy boolean is enabled");
@@ -276,7 +276,7 @@ static void BeautyControlInteractionTests(void) {
Check(api.actionDepth==0 && api.actionStarts==api.actionEnds && api.accessViolations==0,@"all new numeric, bypass, reset and master interactions use balanced host actions"); Check(api.actionDepth==0 && api.actionStarts==api.actionEnds && api.accessViolations==0,@"all new numeric, bypass, reset and master interactions use balanced host actions");
} }
static void HostHandshakeTests(void) { static void HostHandshakeTests(void) {
PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil]; PGInspectorTestAPI *api=[PGInspectorTestAPI new];FCPBeautyGirlPlugIn *plugin=[[FCPBeautyGirlPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.values[@(PGMidtone)]=@.5; api.values[@(PGMidtone)]=@.5;
api.parameterAPIsRequireAction=YES;api.actionRequiresView=YES; api.parameterAPIsRequireAction=YES;api.actionRequiresView=YES;
PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost]; PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
@@ -293,7 +293,7 @@ static void HostHandshakeTests(void) {
Check(api.accessViolations==0 && api.actionDepth==0 && api.actionStarts==api.actionEnds,@"action-scoped connection, edits, failure and reconnection remain balanced"); Check(api.accessViolations==0 && api.actionDepth==0 && api.actionStarts==api.actionEnds,@"action-scoped connection, edits, failure and reconnection remain balanced");
} }
static void ContinuousPreviewTests(void) { static void ContinuousPreviewTests(void) {
PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil]; PGInspectorTestAPI *api=[PGInspectorTestAPI new];FCPBeautyGirlPlugIn *plugin=[[FCPBeautyGirlPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.parameterAPIsRequireAction=YES;api.actionRequiresView=YES; api.parameterAPIsRequireAction=YES;api.actionRequiresView=YES;
PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost]; PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
NSArray *names=@[@"短脸",@"五官保护",@"非肤色区保护",@"微细锐化"],*ids=@[@(PGShort),@(PGFeatureProtectionAmount),@(PGNonSkinProtection),@(PGMicroDetail)]; NSArray *names=@[@"短脸",@"五官保护",@"非肤色区保护",@"微细锐化"],*ids=@[@(PGShort),@(PGFeatureProtectionAmount),@(PGNonSkinProtection),@(PGMicroDetail)];
@@ -319,7 +319,7 @@ static void ContinuousPreviewTests(void) {
static void OptionalInspectorPreview(void) { static void OptionalInspectorPreview(void) {
NSString *path=NSProcessInfo.processInfo.environment[@"PAINTFCP_INSPECTOR_PNG"]; NSString *path=NSProcessInfo.processInfo.environment[@"PAINTFCP_INSPECTOR_PNG"];
if(!path.length)return; if(!path.length)return;
PGHostAPI *api=[PGHostAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil]; PGHostAPI *api=[PGHostAPI new];FCPBeautyGirlPlugIn *plugin=[[FCPBeautyGirlPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
api.values[@(PGMidtone)]=@.4; api.values[@(PGMidtone)]=@.4;
PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost]; PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
[view setFrameSize:NSMakeSize(380,20)]; [view setFrameSize:NSMakeSize(380,20)];
+104
查看文件
@@ -0,0 +1,104 @@
"""Run the generated installer migration in isolated volumes, never live paths."""
import os, pathlib, plistlib, shlex, subprocess, sys, tempfile, unittest
ROOT = pathlib.Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / 'scripts'))
from installer_identity import inject_migration, PRODUCT
class InstallerIdentityTests(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory(prefix='beautygirl-installer-test.')
self.root = pathlib.Path(self.tmp.name)
self.old = self.root / pathlib.Path(PRODUCT['legacyProducts'][0]['installationPath']).relative_to('/')
self.new = self.root / pathlib.Path(PRODUCT['installationPath']).relative_to('/')
for app, info in [(self.old, PRODUCT['legacyProducts'][0]), (self.new, PRODUCT)]:
(app / 'Contents/PlugIns' / info['pluginName'] / 'Contents').mkdir(parents=True)
(app / 'Contents/Info.plist').write_bytes(plistlib.dumps({'CFBundleIdentifier': info['bundleIdentifier']}))
(app / 'Contents/PlugIns' / info['pluginName'] / 'Contents/Info.plist').write_bytes(plistlib.dumps({'ProPlugPlugInList': [{'uuid': PRODUCT['filterUUID']}]}))
(app / 'payload-byte').write_bytes(b'original signed payload stand-in')
self.signer = self.root / 'codesign-fixture'
self.signer.write_text('#!/bin/zsh\napp="${argv[-1]}"\nif [[ -f "$app/.invalid" ]]; then exit 1; fi\n/bin/echo TeamIdentifier=B3W25FX5H5 >&2\n')
self.signer.chmod(0o755)
def tearDown(self):
self.tmp.cleanup()
def run_installer(self, fail_registration=False):
base = '''#!/bin/zsh
set -eu
TARGET_VOLUME=@@VOLUME@@
CONSOLE_UID=501
CONSOLE_USER=fixture
FX_FAILURE=0
fx_verify_app() {
/bin/echo "$1" >> @@LOG@@
if [[ "$1" == "$BG_NEW_APP" && @@FAIL@@ == 1 ]]; then return 1; fi
return 0
}
trap - EXIT
fx_verify_app "${TARGET_VOLUME}/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app" || FX_FAILURE=1
if (( FX_FAILURE )); then exit 1; fi
exit 0
'''
base = base.replace('@@VOLUME@@', shlex.quote(str(self.root))).replace('@@LOG@@', shlex.quote(str(self.root / 'registration-calls'))).replace('@@FAIL@@', '1' if fail_registration else '0')
code = inject_migration(base)
# Only signature and user-session registration are isolated. Identity
# parsing, file moves, deletes, traps and rollback run unchanged.
code = code.replace('/usr/bin/codesign', shlex.quote(str(self.signer)))
code = code.replace('/bin/launchctl asuser', '/usr/bin/true asuser')
script = self.root / 'postinstall'
script.write_text(code)
subprocess.run(['/bin/zsh', '-n', str(script)], check=True, capture_output=True)
return subprocess.run(['/bin/zsh', str(script)], text=True, capture_output=True)
def test_upgrade_keeps_new_and_removes_old_and_recovery_copy(self):
self.assertEqual(self.run_installer().returncode, 0)
self.assertTrue(self.new.exists())
self.assertFalse(self.old.exists())
self.assertFalse(list((self.root / 'Library/Application Support').rglob('*.app')))
def test_registration_failure_restores_old_and_removes_new(self):
original = (self.old / 'payload-byte').read_bytes()
result = self.run_installer(True)
self.assertNotEqual(result.returncode, 0)
self.assertFalse(self.new.exists())
self.assertEqual((self.old / 'payload-byte').read_bytes(), original)
self.assertIn(str(self.old), (self.root / 'registration-calls').read_text())
def test_invalid_new_signature_does_not_touch_old(self):
(self.new / '.invalid').touch()
self.assertNotEqual(self.run_installer().returncode, 0)
self.assertTrue(self.old.exists())
def test_foreign_old_bundle_id_is_preserved(self):
(self.old / 'Contents/Info.plist').write_bytes(plistlib.dumps({'CFBundleIdentifier': 'com.unrelated.product'}))
self.assertNotEqual(self.run_installer().returncode, 0)
self.assertTrue(self.old.exists())
def test_invalid_old_signature_is_preserved(self):
(self.old / '.invalid').touch()
self.assertNotEqual(self.run_installer().returncode, 0)
self.assertTrue(self.old.exists())
def test_fresh_install_and_repeat_are_idempotent(self):
import shutil
shutil.rmtree(self.old)
self.assertEqual(self.run_installer().returncode, 0)
self.assertEqual(self.run_installer().returncode, 0)
self.assertTrue(self.new.exists())
def test_unrelated_neighbor_is_preserved(self):
unrelated = self.old.parent / 'OtherProduct.app'
unrelated.mkdir()
self.assertEqual(self.run_installer().returncode, 0)
self.assertTrue(unrelated.exists())
@unittest.skipUnless(os.environ.get('FCP_BEAUTYGIRL_POSTINSTALL'), 'Final PKG is not built yet')
def test_final_package_contains_the_tested_migration_block(self):
actual = pathlib.Path(os.environ['FCP_BEAUTYGIRL_POSTINSTALL']).read_text()
generated = inject_migration('\ntrap - EXIT\nfx_verify_app candidate\nexit 0\n')
start = generated.index('# FCP-BeautyGirl identity migration.')
end = generated.rindex('\nfx_verify_app ')
self.assertIn(generated[start:end], actual)
if __name__ == '__main__':
unittest.main()