android app for otb-cloud uploading
https://otb-cloud.outsidethebox.top/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
7.4 KiB
182 lines
7.4 KiB
cd /home/def/outsidethebox/otb-cloud-android || exit 1 |
|
set -e |
|
|
|
BACKUPDIR="/home/def/backuphere/otb-cloud-android" |
|
mkdir -p "$BACKUPDIR" |
|
mkdir -p /home/def/outsidethebox/apk-drop |
|
|
|
echo "===== BACKUP =====" |
|
cp /home/def/outsidethebox/otb-cloud-android/app/src/main/java/top/outsidethebox/otbcloud/MainActivity.kt \ |
|
"$BACKUPDIR/MainActivity.kt.$(date +%Y%m%d-%H%M%S).bak" |
|
cp /home/def/outsidethebox/otb-cloud-android/app/build.gradle \ |
|
"$BACKUPDIR/app.build.gradle.$(date +%Y%m%d-%H%M%S).bak" |
|
cp /home/def/outsidethebox/otb-cloud-android/app/src/main/AndroidManifest.xml \ |
|
"$BACKUPDIR/AndroidManifest.xml.$(date +%Y%m%d-%H%M%S).bak" |
|
cp /home/def/outsidethebox/otb-cloud-android/app/src/main/res/layout/activity_main.xml \ |
|
"$BACKUPDIR/activity_main.xml.$(date +%Y%m%d-%H%M%S).bak" |
|
|
|
echo "===== PATCH MainActivity.kt =====" |
|
python3 - << 'PY' |
|
from pathlib import Path |
|
import re |
|
|
|
p = Path("/home/def/outsidethebox/otb-cloud-android/app/src/main/java/top/outsidethebox/otbcloud/MainActivity.kt") |
|
text = p.read_text() |
|
|
|
text = re.sub(r'private const val VIDEO_BATCH_SIZE = \d+', 'private const val VIDEO_BATCH_SIZE = 2', text) |
|
text = re.sub(r'private const val IMAGE_BATCH_SIZE = \d+', 'private const val IMAGE_BATCH_SIZE = 25', text) |
|
text = re.sub(r'private const val PAUSE_BETWEEN_BATCHES_MS = \d+L', 'private const val PAUSE_BETWEEN_BATCHES_MS = 1500L', text) |
|
|
|
if 'private const val PAUSE_BETWEEN_FILES_MS' not in text: |
|
text = text.replace( |
|
'private const val PAUSE_BETWEEN_BATCHES_MS = 1500L', |
|
'private const val PAUSE_BETWEEN_BATCHES_MS = 1500L\n private const val PAUSE_BETWEEN_FILES_MS = 300L' |
|
) |
|
|
|
pattern = re.compile( |
|
r'private fun uploadSelectedMedia\(selected: List<MediaItem>\) \{.*?\n \}', |
|
re.S |
|
) |
|
|
|
replacement = ''' |
|
private fun uploadSelectedMedia(selected: List<MediaItem>) { |
|
val prefs = getPrefs() |
|
val deviceUuid = prefs.getString(KEY_DEVICE_UUID, null) |
|
|
|
if (deviceUuid.isNullOrBlank()) { |
|
binding.statusText.text = "Missing local device UUID" |
|
Toast.makeText(this, "Missing device UUID", Toast.LENGTH_LONG).show() |
|
return |
|
} |
|
|
|
binding.uploadSelectedButton.isEnabled = false |
|
binding.scanButton.isEnabled = false |
|
binding.runScanButton.isEnabled = false |
|
binding.selectAllButton.isEnabled = false |
|
binding.clearAllButton.isEnabled = false |
|
|
|
executor.execute { |
|
var uploaded = 0 |
|
var skipped = 0 |
|
var failed = 0 |
|
|
|
val containsVideo = selected.any { it.mimeType.startsWith("video/") } |
|
val batchSize = if (containsVideo) VIDEO_BATCH_SIZE else IMAGE_BATCH_SIZE |
|
val batches = selected.chunked(batchSize) |
|
|
|
for ((batchIndex, batch) in batches.withIndex()) { |
|
runOnUiThread { |
|
binding.statusText.text = |
|
"Starting batch ${batchIndex + 1} of ${batches.size} (${batch.size} file(s))" |
|
} |
|
|
|
for ((itemIndex, item) in batch.withIndex()) { |
|
runOnUiThread { |
|
binding.statusText.text = |
|
"Batch ${batchIndex + 1}/${batches.size} - File ${itemIndex + 1}/${batch.size}: ${item.displayName}" |
|
} |
|
|
|
if (serverFileExists(deviceUuid, item)) { |
|
skipped += 1 |
|
runOnUiThread { |
|
binding.statusText.text = |
|
"Batch ${batchIndex + 1}/${batches.size} - Skipping existing: ${item.displayName}" |
|
} |
|
} else { |
|
val ok = uploadSingleFile(deviceUuid, item) |
|
if (ok) { |
|
uploaded += 1 |
|
} else { |
|
failed += 1 |
|
} |
|
} |
|
|
|
try { |
|
Thread.sleep(PAUSE_BETWEEN_FILES_MS) |
|
} catch (_: Exception) { |
|
} |
|
|
|
System.gc() |
|
} |
|
|
|
if (batchIndex < batches.lastIndex) { |
|
runOnUiThread { |
|
binding.statusText.text = |
|
"Completed batch ${batchIndex + 1}/${batches.size}. Pausing before next batch..." |
|
} |
|
try { |
|
Thread.sleep(PAUSE_BETWEEN_BATCHES_MS) |
|
} catch (_: Exception) { |
|
} |
|
System.gc() |
|
} |
|
} |
|
|
|
runOnUiThread { |
|
binding.uploadSelectedButton.isEnabled = true |
|
binding.scanButton.isEnabled = true |
|
binding.runScanButton.isEnabled = true |
|
binding.selectAllButton.isEnabled = true |
|
binding.clearAllButton.isEnabled = true |
|
binding.statusText.text = "Upload complete: $uploaded uploaded, $skipped skipped, $failed failed" |
|
Toast.makeText( |
|
this, |
|
"Upload complete: $uploaded uploaded, $skipped skipped, $failed failed", |
|
Toast.LENGTH_LONG |
|
).show() |
|
} |
|
} |
|
}''' |
|
|
|
new_text, count = pattern.subn(replacement, text, count=1) |
|
if count != 1: |
|
raise SystemExit("FAILED: could not replace uploadSelectedMedia function") |
|
p.write_text(new_text) |
|
print("MainActivity.kt updated") |
|
PY |
|
|
|
echo "===== PATCH VERSION FILES TO v0.2.2 =====" |
|
python3 - << 'PY' |
|
from pathlib import Path |
|
import re |
|
|
|
files = [ |
|
Path("/home/def/outsidethebox/otb-cloud-android/app/build.gradle"), |
|
Path("/home/def/outsidethebox/otb-cloud-android/app/src/main/AndroidManifest.xml"), |
|
Path("/home/def/outsidethebox/otb-cloud-android/app/src/main/res/layout/activity_main.xml"), |
|
] |
|
|
|
for p in files: |
|
text = p.read_text() |
|
text = re.sub(r'versionCode\s+\d+', 'versionCode 22', text) |
|
text = re.sub(r'versionName\s+"[^"]+"', 'versionName "0.2.2"', text) |
|
text = text.replace('OTB Cloud v0.2.1', 'OTB Cloud v0.2.2') |
|
text = text.replace('OTB Cloud v0.2.0', 'OTB Cloud v0.2.2') |
|
text = text.replace('OTB Cloud v0.1.9', 'OTB Cloud v0.2.2') |
|
text = text.replace('Android Backup Client v0.2.1', 'Android Backup Client v0.2.2') |
|
text = text.replace('Android Backup Client v0.2.0', 'Android Backup Client v0.2.2') |
|
text = text.replace('Android Backup Client v0.1.9', 'Android Backup Client v0.2.2') |
|
p.write_text(text) |
|
|
|
print("Version files updated") |
|
PY |
|
|
|
echo "===== VERIFY SOURCE =====" |
|
grep -n 'VIDEO_BATCH_SIZE\|IMAGE_BATCH_SIZE\|PAUSE_BETWEEN_BATCHES_MS\|PAUSE_BETWEEN_FILES_MS' \ |
|
/home/def/outsidethebox/otb-cloud-android/app/src/main/java/top/outsidethebox/otbcloud/MainActivity.kt |
|
grep -nE 'versionCode|versionName' /home/def/outsidethebox/otb-cloud-android/app/build.gradle |
|
grep -n 'android:label=' /home/def/outsidethebox/otb-cloud-android/app/src/main/AndroidManifest.xml |
|
|
|
echo "===== BUILD =====" |
|
cd /home/def/outsidethebox/otb-cloud-android || exit 1 |
|
./gradlew clean assembleDebug --no-daemon |
|
|
|
echo "===== COPY APK =====" |
|
cp /home/def/outsidethebox/otb-cloud-android/app/build/outputs/apk/debug/app-debug.apk \ |
|
/home/def/outsidethebox/apk-drop/otb-cloud-v0.2.2.apk |
|
|
|
echo "===== VERIFY APK =====" |
|
aapt dump badging /home/def/outsidethebox/otb-cloud-android/app/build/outputs/apk/debug/app-debug.apk 2>/dev/null | grep version || true |
|
|
|
echo "===== FINAL APK =====" |
|
ls -lh /home/def/outsidethebox/apk-drop/otb-cloud-v0.2.2.apk
|
|
|