mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-27 20:40:12 +00:00
fix: harden media download flow
This commit is contained in:
@@ -4,8 +4,10 @@ set -euo pipefail
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
APP_NAME="Firelink"
|
||||
CONFIGURATION="${CONFIGURATION:-release}"
|
||||
MARKETING_VERSION="${MARKETING_VERSION:-0.1.0}"
|
||||
BUILD_NUMBER="${BUILD_NUMBER:-1}"
|
||||
DEFAULT_MARKETING_VERSION="$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || true)"
|
||||
DEFAULT_BUILD_NUMBER="$(git rev-list --count HEAD 2>/dev/null || true)"
|
||||
MARKETING_VERSION="${MARKETING_VERSION:-${DEFAULT_MARKETING_VERSION:-0.1.0}}"
|
||||
BUILD_NUMBER="${BUILD_NUMBER:-${DEFAULT_BUILD_NUMBER:-1}}"
|
||||
APP_DIR="$ROOT_DIR/build/$APP_NAME.app"
|
||||
CONTENTS_DIR="$APP_DIR/Contents"
|
||||
MACOS_DIR="$CONTENTS_DIR/MacOS"
|
||||
@@ -35,12 +37,12 @@ ARIA2C_PATH=$(which aria2c || true)
|
||||
if [[ -n "$ARIA2C_PATH" && -x "$ARIA2C_PATH" ]]; then
|
||||
echo "Bundling aria2c from $ARIA2C_PATH..."
|
||||
cp "$ARIA2C_PATH" "$RESOURCES_DIR/aria2c"
|
||||
|
||||
|
||||
if ! command -v dylibbundler &> /dev/null; then
|
||||
echo "Installing dylibbundler..."
|
||||
brew install dylibbundler
|
||||
fi
|
||||
|
||||
|
||||
FRAMEWORKS_DIR="$CONTENTS_DIR/Frameworks"
|
||||
mkdir -p "$FRAMEWORKS_DIR"
|
||||
dylibbundler -od -b -x "$RESOURCES_DIR/aria2c" -d "$FRAMEWORKS_DIR" -p "@executable_path/../Frameworks/"
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import re
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# Remove doubleClickableCell block
|
||||
content = re.sub(r' private func doubleClickableCell.*? }\n\n', '', content, flags=re.DOTALL)
|
||||
|
||||
# Remove doubleClickableCell wrappers from TableColumn
|
||||
content = re.sub(r'doubleClickableCell\(for: item\) \{\n\s*(.*?)\n\s*\}', r'\1', content, flags=re.DOTALL)
|
||||
|
||||
# Add simultaneousGesture to Table
|
||||
table_end = content.find(' .environment(\\.defaultMinListRowHeight, settings.listRowDensity.minRowHeight)')
|
||||
gesture = ''' .simultaneousGesture(TapGesture(count: 2).onEnded {
|
||||
if let id = selection.first, let item = controller.downloads.first(where: { $0.id == id }) {
|
||||
performPrimaryAction(for: item)
|
||||
}
|
||||
})
|
||||
'''
|
||||
content = content[:table_end] + gesture + content[table_end:]
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "w") as f:
|
||||
f.write(content)
|
||||
@@ -1,62 +0,0 @@
|
||||
import re
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# Fix size to use bytesText if sizeBytes is nil or 0
|
||||
old_size = ''' TableColumn("Size", value: \\.sortableSize) { item in
|
||||
Text(ByteFormatter.string(item.sizeBytes))
|
||||
.monospacedDigit()
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
}'''
|
||||
new_size = ''' TableColumn("Size", value: \\.sortableSize) { item in
|
||||
if let size = item.sizeBytes, size > 0 {
|
||||
Text(ByteFormatter.string(size))
|
||||
.monospacedDigit()
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
} else if item.bytesText != "-" && !item.bytesText.isEmpty {
|
||||
Text(item.bytesText)
|
||||
.monospacedDigit()
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
} else {
|
||||
Text("Unknown")
|
||||
.monospacedDigit()
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
}
|
||||
}'''
|
||||
content = content.replace(old_size, new_size)
|
||||
|
||||
# Add allowsHitTesting(false) to text to fix single click interception
|
||||
old_text = ''' Text(item.fileName)
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)'''
|
||||
new_text = ''' Text(item.fileName)
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.allowsHitTesting(false)'''
|
||||
content = content.replace(old_text, new_text)
|
||||
|
||||
# Change performPrimaryAction to use id
|
||||
old_action = 'openWindow(value: item.id)'
|
||||
new_action = 'openWindow(id: "download-properties", value: item.id)'
|
||||
content = content.replace(old_action, new_action)
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "w") as f:
|
||||
f.write(content)
|
||||
|
||||
with open("Sources/Firelink/FirelinkApp.swift", "r") as f:
|
||||
app_content = f.read()
|
||||
|
||||
app_content = app_content.replace(
|
||||
'WindowGroup("Download Properties", for: UUID.self)',
|
||||
'WindowGroup("Download Properties", id: "download-properties", for: UUID.self)'
|
||||
)
|
||||
|
||||
with open("Sources/Firelink/FirelinkApp.swift", "w") as f:
|
||||
f.write(app_content)
|
||||
@@ -1,86 +0,0 @@
|
||||
with open("Sources/Firelink/FirelinkApp.swift", "r") as f:
|
||||
app_content = f.read()
|
||||
|
||||
app_content = app_content.replace(
|
||||
'WindowGroup("Download Properties", id: "download-properties", for: String.self) { $downloadIDString in\n if let idString = downloadIDString, let downloadID = UUID(uuidString: idString) {',
|
||||
'WindowGroup("Download Properties", id: "download-properties", for: UUID.self) { $downloadID in\n if let downloadID {'
|
||||
)
|
||||
|
||||
with open("Sources/Firelink/FirelinkApp.swift", "w") as f:
|
||||
f.write(app_content)
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "r") as f:
|
||||
table_content = f.read()
|
||||
|
||||
# Fix openWindow in performPrimaryAction
|
||||
table_content = table_content.replace(
|
||||
'openWindow(id: "download-properties", value: item.id.uuidString)',
|
||||
'openWindow(id: "download-properties", value: item.id)'
|
||||
)
|
||||
|
||||
# Fix openWindow in rowContextMenu
|
||||
table_content = table_content.replace(
|
||||
'openWindow(value: target.id)',
|
||||
'openWindow(id: "download-properties", value: target.id)'
|
||||
)
|
||||
|
||||
# Remove simultaneousGesture from Table
|
||||
import re
|
||||
table_content = re.sub(
|
||||
r'\s*\.simultaneousGesture\(TapGesture\(count: 2\)\.onEnded \{\s*if let id = selection\.first, let item = controller\.downloads\.first\(where: \{ \$0\.id == id \}\) \{\s*performPrimaryAction\(for: item\)\s*\}\s*\}\)',
|
||||
'',
|
||||
table_content
|
||||
)
|
||||
|
||||
# Replace the File Name TableColumn to use doubleClickableCell
|
||||
old_column = ''' TableColumn("File Name", value: \\.fileName) { item in
|
||||
HStack(alignment: .top, spacing: 8) {
|
||||
Image(systemName: item.category.symbolName)
|
||||
.font(.title3)
|
||||
.foregroundStyle(categoryColor(for: item.category))
|
||||
.frame(width: 22)
|
||||
Text(item.fileName)
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.allowsHitTesting(false)
|
||||
.draggable(item.id.uuidString)
|
||||
}
|
||||
}'''
|
||||
|
||||
new_column = ''' TableColumn("File Name", value: \\.fileName) { item in
|
||||
doubleClickableCell(for: item) {
|
||||
HStack(alignment: .top, spacing: 8) {
|
||||
Image(systemName: item.category.symbolName)
|
||||
.font(.title3)
|
||||
.foregroundStyle(categoryColor(for: item.category))
|
||||
.frame(width: 22)
|
||||
Text(item.fileName)
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
.draggable(item.id.uuidString)
|
||||
}
|
||||
}'''
|
||||
|
||||
table_content = table_content.replace(old_column, new_column)
|
||||
|
||||
# Add doubleClickableCell helper
|
||||
helper = ''' private func performPrimaryAction(for item: DownloadItem) {'''
|
||||
|
||||
helper_new = ''' private func doubleClickableCell<Content: View>(for item: DownloadItem, @ViewBuilder content: () -> Content) -> some View {
|
||||
content()
|
||||
.contentShape(Rectangle())
|
||||
.simultaneousGesture(TapGesture(count: 2).onEnded {
|
||||
performPrimaryAction(for: item)
|
||||
})
|
||||
}
|
||||
|
||||
private func performPrimaryAction(for item: DownloadItem) {'''
|
||||
|
||||
table_content = table_content.replace(helper, helper_new)
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "w") as f:
|
||||
f.write(table_content)
|
||||
@@ -1,21 +0,0 @@
|
||||
with open("Sources/Firelink/FirelinkApp.swift", "r") as f:
|
||||
app_content = f.read()
|
||||
|
||||
old_group = ''' WindowGroup("Download Properties", id: "download-properties", for: UUID.self) { $downloadID in
|
||||
if let downloadID {'''
|
||||
new_group = ''' WindowGroup("Download Properties", id: "download-properties", for: String.self) { $downloadIDString in
|
||||
if let idString = downloadIDString, let downloadID = UUID(uuidString: idString) {'''
|
||||
app_content = app_content.replace(old_group, new_group)
|
||||
|
||||
with open("Sources/Firelink/FirelinkApp.swift", "w") as f:
|
||||
f.write(app_content)
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "r") as f:
|
||||
table_content = f.read()
|
||||
|
||||
old_open1 = 'openWindow(id: "download-properties", value: item.id)'
|
||||
new_open1 = 'openWindow(id: "download-properties", value: item.id.uuidString)'
|
||||
table_content = table_content.replace(old_open1, new_open1)
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "w") as f:
|
||||
f.write(table_content)
|
||||
@@ -1,45 +0,0 @@
|
||||
with open("Sources/Firelink/DownloadTable.swift", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
old_column = ''' TableColumn("File Name", value: \\.fileName) { item in
|
||||
doubleClickableCell(for: item) {
|
||||
HStack(alignment: .top, spacing: 8) {
|
||||
Image(systemName: item.category.symbolName)
|
||||
.font(.title3)
|
||||
.foregroundStyle(categoryColor(for: item.category))
|
||||
.frame(width: 22)
|
||||
Text(item.fileName)
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
.draggable(item.id.uuidString)
|
||||
}
|
||||
}'''
|
||||
|
||||
new_column = ''' TableColumn("File Name", value: \\.fileName) { item in
|
||||
HStack(alignment: .top, spacing: 8) {
|
||||
Image(systemName: item.category.symbolName)
|
||||
.font(.title3)
|
||||
.foregroundStyle(categoryColor(for: item.category))
|
||||
.frame(width: 22)
|
||||
Text(item.fileName)
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
.draggable(item.id.uuidString)
|
||||
}'''
|
||||
|
||||
content = content.replace(old_column, new_column)
|
||||
|
||||
import re
|
||||
|
||||
# Remove doubleClickableCell function block
|
||||
pattern = r'\s*private func doubleClickableCell<Content: View>\(for item: DownloadItem, @ViewBuilder content: \(\) -> Content\) -> some View \{\s*content\(\)\s*\.contentShape\(Rectangle\(\)\)\s*\.simultaneousGesture\(TapGesture\(count: 2\)\.onEnded \{\s*performPrimaryAction\(for: item\)\s*\}\)\s*\}'
|
||||
content = re.sub(pattern, '', content)
|
||||
|
||||
with open("Sources/Firelink/DownloadTable.swift", "w") as f:
|
||||
f.write(content)
|
||||
@@ -5,4 +5,5 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
swift build
|
||||
git diff --check
|
||||
python3 -m json.tool Extensions/Firefox/manifest.json >/dev/null
|
||||
|
||||
Reference in New Issue
Block a user