比较提交
8
次代码提交
b35b4a5d1c
...
v1.3.2
| 作者 | SHA1 | 提交日期 | |
|---|---|---|---|
|
|
8a70d38b7c | ||
|
|
767bba8ac1 | ||
|
|
47f6e55ecd | ||
|
|
d1137edd83 | ||
|
|
2faf7de779 | ||
|
|
e47736222d | ||
|
|
6a29d52a9a | ||
|
|
cd2e608ec6 |
没有与搜索条件相匹配的文件
+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
|
||||||
+48
-48
@@ -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;
|
||||||
};
|
};
|
||||||
文件已重命名,内容未更改。
+1
-1
@@ -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;
|
||||||
+4
-4
@@ -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>
|
||||||
文件已重命名,内容未更改。
文件已重命名,内容未更改。
文件已重命名,内容未更改。
文件已重命名,内容未更改。
+1
-1
@@ -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
-1
@@ -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.
|
||||||
//
|
//
|
||||||
+1
-1
@@ -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];
|
||||||
+7
-7
@@ -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
-2
@@ -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>
|
||||||
文件已重命名,内容未更改。
文件已重命名,内容未更改。
文件已重命名,内容未更改。
文件已重命名,内容未更改。
文件已重命名,内容未更改。
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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,保留隔离属性
|
||||||
|
|
||||||
|
识别完成,未生成安装包。
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,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,
|
||||||
|
|||||||
@@ -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 -->
|
||||||
@@ -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 -->
|
||||||
|
|||||||
二进制文件未显示。
@@ -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 及相关资源遵循各自许可。
|
||||||
@@ -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": "免费开源,无需激活码"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -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:]
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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 \
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 + '"'
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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)];
|
||||||
|
|||||||
@@ -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()
|
||||||
在新工单中引用
屏蔽一个用户