Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

<!-- The "## vX.Y.Z" section is the release notes and the Telegram post (.github/scripts/telegram-release.sh): keep it short. -->

## v2.5.1
- أول إصدار رسمي: الإضافة طلعت من التجريبي (Beta)
- زر «حذف» لكل نسخة احتياطية في تبويب الباك أب، مع تأكيد قبل الحذف
- أمر fbs delete يحذف نسخة وحدة من مجلد Backups بس

**English**
- First stable release: the module is out of beta
- A Delete button for each backup in the Backup tab, with a confirmation first
- fbs delete removes one backup, and only inside the Backups folder

## v2.5.0
- متوافق مع صفحة «الجوال» في Fastboot Studio v2.5.0: المواصفات والحماية والتعارضات والنسخ الاحتياطية
- النسخة الاحتياطية تنكتب في مجلد مخفي وما يطلع اسمها إلا لما تكتمل، فالبرنامج ما ينقل نسخة ناقصة
Expand Down
9 changes: 6 additions & 3 deletions README.ar.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<img alt="Magisk | KernelSU | APatch" src="https://img.shields.io/badge/root-Magisk%20%7C%20KernelSU%20%7C%20APatch-0E1116?style=flat-square&labelColor=1D222B">
<img alt="Languages" src="https://img.shields.io/badge/UI-English%20%7C%20%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9-0E1116?style=flat-square&labelColor=1D222B">
<a href="https://github.com/ifoknr/FastbootStudio-Companion/releases"><img alt="Latest release" src="https://img.shields.io/github/v/release/ifoknr/FastbootStudio-Companion?include_prereleases&style=flat-square&labelColor=1D222B&color=2DD4BF&label=release"></a>
<img alt="Beta" src="https://img.shields.io/badge/status-beta-0E1116?style=flat-square&labelColor=1D222B&color=F5C451">
<img alt="Stable" src="https://img.shields.io/badge/status-stable-0E1116?style=flat-square&labelColor=1D222B&color=2DD4BF">
<img alt="License MIT" src="https://img.shields.io/badge/license-MIT-0E1116?style=flat-square&labelColor=1D222B">
<a href="https://t.me/BeNeXTBrO"><img alt="Telegram group" src="https://img.shields.io/badge/Telegram-group-0E1116?style=flat-square&labelColor=1D222B&color=229ED9"></a>
</p>
Expand All @@ -26,8 +26,11 @@
**للقراءة فقط.** ما يشتغل شي وقت الإقلاع (لا `service.sh` ولا `post-fs-data.sh`)، فما يسبب بوت
لوب، وما يكتب على أي بارتشن. الكتابة الوحيدة هي النسخ الاحتياطية والتقارير في `/sdcard/FastbootStudio`.

> 🧪 **تجريبي.** الوحدة في مرحلة تجريبية، وأرقام إصداراتها تمشي مع أرقام Fastboot Studio،
> وإصداراتها تنزل كإصدارات تجريبية لين تصير مستقرة.
> ✅ **مستقرة من 2.5.1.** وأرقام إصداراتها تمشي مع أرقام Fastboot Studio.
>
> **الجديد في 2.5.1:**
> - طلعت من التجريبي: أول إصدار رسمي.
> - تحذف النسخة الاحتياطية من الجوال مباشرة من تبويب الباك أب (`fbs delete`).
>
> **الجديد في 2.5:**
> - متوافقة مع صفحة **الجوال** في Fastboot Studio 2.5: المواصفات والحماية والتعارضات والنسخ الاحتياطية.
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<img alt="Magisk | KernelSU | APatch" src="https://img.shields.io/badge/root-Magisk%20%7C%20KernelSU%20%7C%20APatch-0E1116?style=flat-square&labelColor=1D222B">
<img alt="Languages" src="https://img.shields.io/badge/UI-English%20%7C%20%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9-0E1116?style=flat-square&labelColor=1D222B">
<a href="https://github.com/ifoknr/FastbootStudio-Companion/releases"><img alt="Latest release" src="https://img.shields.io/github/v/release/ifoknr/FastbootStudio-Companion?include_prereleases&style=flat-square&labelColor=1D222B&color=2DD4BF&label=release"></a>
<img alt="Beta" src="https://img.shields.io/badge/status-beta-0E1116?style=flat-square&labelColor=1D222B&color=F5C451">
<img alt="Stable" src="https://img.shields.io/badge/status-stable-0E1116?style=flat-square&labelColor=1D222B&color=2DD4BF">
<img alt="License MIT" src="https://img.shields.io/badge/license-MIT-0E1116?style=flat-square&labelColor=1D222B">
<a href="https://t.me/BeNeXTBrO"><img alt="Telegram group" src="https://img.shields.io/badge/Telegram-group-0E1116?style=flat-square&labelColor=1D222B&color=229ED9"></a>
</p>
Expand All @@ -25,8 +25,11 @@ its partitions in the same layout the Windows app uses, all from the phone itsel
cannot cause a bootloop, and it never writes to a partition. The only writes are backups and
reports under `/sdcard/FastbootStudio`.

> 🧪 **Beta.** The module is experimental. Its version numbers go along with Fastboot Studio's,
> and releases are published as pre-releases until it is marked stable.
> ✅ **Stable since 2.5.1.** Its version numbers go along with Fastboot Studio's.
>
> **New in 2.5.1:**
> - Out of beta: the first stable release.
> - Delete a backup from the phone right in the Backup tab (`fbs delete`).
>
> **New in 2.5:**
> - Works with the **Phone** page in Fastboot Studio 2.5: specs, security, conflicts and backups.
Expand Down
6 changes: 4 additions & 2 deletions module/bin/fbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
# (or one JSON object per line for long jobs), so all three always agree. Nothing here writes
# to a partition: the only writes are backups and reports under /sdcard/FastbootStudio.

FBS_VERSION=2.5.0
FBS_VERSION=2.5.1
# beta while the module is experimental; stable once it is not. release.yml publishes a beta
# as a pre-release, the WebUI shows a Beta badge, and tools/build.sh checks module.prop agrees.
FBS_CHANNEL=beta
FBS_CHANNEL=stable
FBS_LIB=${FBS_LIB:-${0%/*}/../lib}

# shellcheck source=SCRIPTDIR/../lib/common.sh
Expand Down Expand Up @@ -44,6 +44,7 @@ fbs $FBS_VERSION ($FBS_CHANNEL), Fastboot Studio Companion
backups the backups on the phone (JSON)
modules installed modules and the conflicts between them (JSON)
verify <folder> re-check a backup against its SHA256SUMS (JSON lines)
delete <folder> remove one backup from the phone (JSON)
reboot bootloader|fastboot|recovery|edl
bundle [plain] logs and device info for a bug report, IMEI and serial masked
open <https url> open a link in the app that owns it (Telegram, the browser)
Expand All @@ -66,6 +67,7 @@ case $cmd in
backups) backups_json ;;
modules) modules_json ;;
verify) verify_run "$@" ;;
delete) delete_run "$@" ;;
reboot) reboot_to "$@" ;;
bundle) bundle_run "$@" ;;
open) open_url "$@" ;;
Expand Down
22 changes: 22 additions & 0 deletions module/lib/backup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,28 @@ backups_json() {
printf ']}\n'
}

# fbs delete <folder name>: removes one finished backup. Only a folder directly under Backups,
# never an unfinished .partial- one (the running backup cleans those up itself).
delete_run() {
case $1 in
'' | */* | .*)
echo '{"ok":false,"msg":"usage: fbs delete <folder name>"}'
return 2
;;
esac
_out=$DATA/Backups/$1
if [ ! -d "$_out" ]; then
echo '{"ok":false,"msg":"missing"}'
return 1
fi
if rm -rf "$_out"; then
printf '{"ok":true,"folder":%s}\n' "$(js "$1")"
else
echo '{"ok":false,"msg":"storage"}'
return 1
fi
}

# fbs verify <folder name>: re-hashes every file listed in SHA256SUMS.
verify_run() {
case $1 in
Expand Down
8 changes: 4 additions & 4 deletions module/module.prop
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
id=fastboot_studio_companion
name=Fastboot Studio Companion (Beta)
version=v2.5.0
versionCode=250
name=Fastboot Studio Companion
version=v2.5.1
versionCode=251
author=IFOKNR
description=Beta. Device check, partitions, live kernel log and SHA-256 backups for Fastboot Studio. Read-only, nothing runs at boot. Open the WebUI or press Action.
description=Device check, partitions, live kernel log and SHA-256 backups for Fastboot Studio. Read-only, nothing runs at boot. Open the WebUI or press Action.
updateJson=https://raw.githubusercontent.com/ifoknr/FastbootStudio-Companion/main/update.json
18 changes: 17 additions & 1 deletion module/webroot/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,8 @@ async function loadBackups() {
return;
}
list.innerHTML = b.items.map(x => `<div class="bitem" data-name="${esc(x.name)}"><span class="p">${esc(x.name)}/</span>` +
`<button class="btn-s"${x.sums ? '' : ' disabled'}>${esc(T('backup.verify'))}</button>` +
`<button class="btn-s" data-act="verify"${x.sums ? '' : ' disabled'}>${esc(T('backup.verify'))}</button>` +
`<button class="btn-s danger" data-act="delete">${esc(T('backup.delete'))}</button>` +
`<span class="m">${esc(T('backup.files', x.files, x.kb == null ? '–' : size(x.kb * 1024)))}</span></div>`).join('');
} catch (e) {
list.innerHTML = `<p class="note">${esc(T('err.generic', e.message || e))}</p>`;
Expand All @@ -601,6 +602,7 @@ $('#backupList').addEventListener('click', async e => {
const btn = e.target.closest('button');
if (!btn || btn.disabled) return;
const item = btn.closest('.bitem');
if (btn.dataset.act === 'delete') return askDelete(item.dataset.name);
const meta = item.querySelector('.m');
btn.disabled = true;
btn.textContent = T('backup.verifying');
Expand All @@ -622,6 +624,20 @@ $('#backupList').addEventListener('click', async e => {
: `<span style="color:var(--ok)">✓ ${esc(T('backup.ok', result.ok))}</span>`;
});

function askDelete(name) {
sheet(T('backup.deleteTitle'), `<p class="note">${esc(T('backup.deleteBody', name))}</p>`,
[{ label: T('cancel') }, { label: T('backup.delete'), kind: 'danger', onClick: async () => {
closeSheet();
try {
const r = await fbsJson('delete', name);
toast(r.ok ? T('backup.deleted') : T('err.generic', r.msg));
} catch (e) {
toast(T('err.generic', e.message || e));
}
loadBackups();
} }]);
}

/* ---------------------------------------------------------------- modules */

const Mods = { data: null, busy: false };
Expand Down
10 changes: 8 additions & 2 deletions module/webroot/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
];

const info = {
fbs: '2.5.0', channel: 'beta', model: 'Demo Phone', brand: 'Demo', device: 'demo', product: 'demo_mt6789',
fbs: '2.5.1', channel: 'stable', model: 'Demo Phone', brand: 'Demo', device: 'demo', product: 'demo_mt6789',
android: '14', sdk: '34', patch: '2026-08-05', build: 'DEMO-14.0.1', platform: 'mt6789', soc: 'mediatek',
arch: 'arm64-v8a', slot: '_a', dynamic: true, treble: true, vndk: '34',
boot: { vbstate: 'orange', device_state: 'unlocked', locked: false, spoofed: true },
Expand Down Expand Up @@ -123,6 +123,12 @@
case 'reboot': return JSON.stringify({ ok: true });
case 'open': return JSON.stringify({ ok: true });
case 'modules': return JSON.stringify(modules);
case 'delete': {
const i = backups.findIndex(x => x.name === a1);
if (i < 0) return JSON.stringify({ ok: false, msg: 'missing' });
backups.splice(i, 1);
return JSON.stringify({ ok: true, folder: a1 });
}
default: return '';
}
}
Expand Down Expand Up @@ -152,7 +158,7 @@
const modules = {
root: '/data/adb/modules',
modules: [
m('fastboot_studio_companion', 'Fastboot Studio Companion (Beta)', 'v2.5.0', { webui: true, action: true }),
m('fastboot_studio_companion', 'Fastboot Studio Companion', 'v2.5.1', { webui: true, action: true }),
m('systemless_hosts', 'Systemless Hosts', 'v1.2', { files: 1 }),
m('adblock_plus', 'AdBlock Plus', 'v4.0', { files: 1, props: 2, scripts: ['service.sh'] }),
m('google_sans_font', 'Google Sans Font', 'v3.1', { files: 46 }),
Expand Down
4 changes: 4 additions & 0 deletions module/webroot/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const STRINGS = {
'backup.start': 'Start backup', 'backup.running': 'Backing up…', 'backup.saved': 'Saved backups',
'backup.format': 'Same layout as Fastboot Studio on Windows: its Phone page (v2.5.0 and later) copies a backup to your PC and checks it in one click, and the Device page restores it. Or check it here with sha256sum -c.',
'backup.none': 'No backups yet.', 'backup.verify': 'Verify', 'backup.verifying': 'Checking…',
'backup.delete': 'Delete', 'backup.deleteTitle': 'Delete this backup?', 'backup.deleted': 'Backup deleted',
'backup.deleteBody': '{0} is removed from the phone for good. Copy it to your PC first if you still need it.',
'backup.ok': 'All {0} match', 'backup.bad': '{0} changed or missing', 'backup.files': '{0} files · {1}',
'backup.done': 'Saved {0} images', 'backup.failed': '{0} failed',
'backup.confirm': 'Full backup', 'backup.confirmBody': 'This copies {0} partitions ({1}) to {2}. It can take several minutes.',
Expand Down Expand Up @@ -125,6 +127,8 @@ const STRINGS = {
'backup.start': 'ابدأ الباك أب', 'backup.running': 'جاري النسخ…', 'backup.saved': 'النسخ المحفوظة',
'backup.format': 'نفس صيغة Fastboot Studio في الويندوز: صفحة «الجوال» في البرنامج (v2.5.0 وأحدث) تنقل النسخة للكمبيوتر وتتحقق منها بضغطة، وتسترجعها من صفحة الجهاز. أو تحقق منها هنا بـ sha256sum -c.',
'backup.none': 'ما فيه نسخ للحين.', 'backup.verify': 'تحقق', 'backup.verifying': 'يتحقق…',
'backup.delete': 'حذف', 'backup.deleteTitle': 'تحذف هالنسخة؟', 'backup.deleted': 'انحذفت النسخة',
'backup.deleteBody': '{0} بتنحذف من الجوال نهائياً. انقلها للكمبيوتر أول إذا تحتاجها.',
'backup.ok': 'كلها مطابقة ({0})', 'backup.bad': '{0} متغيّر أو ناقص', 'backup.files': '{0} ملف · {1}',
'backup.done': 'انحفظت {0} صورة', 'backup.failed': '{0} فشلت',
'backup.confirm': 'باك أب كامل', 'backup.confirmBody': 'بينسخ {0} بارتشن ({1}) إلى {2}. ممكن ياخذ كم دقيقة.',
Expand Down
8 changes: 5 additions & 3 deletions module/webroot/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ main { padding: 1rem 1rem calc(var(--bottom) + 6rem); max-width: 1500px; margin:
.fbtn.rules { margin-inline-start: auto; border-color: var(--info-line); color: var(--info); background: var(--info-soft); }
.btn-s { background: var(--raised); border: 1px solid var(--line); border-radius: .7rem; padding: .55rem .9rem; cursor: pointer; font-size: .9rem; color: var(--dim); white-space: nowrap; }
.btn-s[aria-pressed="true"] { color: var(--warn); border-color: var(--warn-line); background: var(--warn-soft); }
.btn-s.danger { color: var(--danger); border-color: var(--danger-line); }
.seg { display: grid; grid-template-columns: 1fr 1fr; background: var(--raised); border: 1px solid var(--line); border-radius: .7rem; padding: .2rem; gap: .2rem; }
.seg.three { grid-template-columns: 1fr 1fr 1fr; }
.seg button { background: none; border: 0; border-radius: .55rem; padding: .5rem; font-size: .9rem; cursor: pointer; color: var(--dim); }
Expand Down Expand Up @@ -190,11 +191,12 @@ main { padding: 1rem 1rem calc(var(--bottom) + 6rem); max-width: 1500px; margin:
.prow .st.ok { color: var(--ok); } .prow .st.bad { color: var(--danger); }

.blist { display: flex; flex-direction: column; gap: .8rem; }
.bitem { display: grid; grid-template-columns: 1fr auto; gap: .15rem .5rem; align-items: center; font-size: .9rem; }
.bitem { display: grid; grid-template-columns: 1fr auto auto; gap: .15rem .5rem; align-items: center; font-size: .9rem; }
.bitem .p { font-family: var(--mono); font-size: .8rem; direction: ltr; unicode-bidi: isolate; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
[dir="rtl"] .bitem .p { text-align: right; }
.bitem .m { color: var(--faint); font-size: .8rem; }
.bitem button { grid-row: span 2; }
.bitem .m { color: var(--faint); font-size: .8rem; grid-column: 1; grid-row: 2; }
.bitem .p { grid-column: 1; grid-row: 1; }
.bitem button { grid-row: 1 / span 2; }

/* Links to the Windows app, the group and a private message. */
.links { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: .5rem; margin-top: .9rem; }
Expand Down
14 changes: 14 additions & 0 deletions tests/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,20 @@ for SHN in $SHELLS; do
out=$(fbs verify ".partial-$name")
expect "verify skips unfinished backups" jqt "$out" '.event == "error"'

# ---- delete
out=$(fbs delete ../etc)
expect "delete stays inside Backups" jqt "$out" '.ok == false'
expect "delete leaves other folders alone" test -d "$WORK/data/Backups"
out=$(fbs delete ".partial-x")
expect "delete refuses hidden folders" jqt "$out" '.ok == false'
out=$(fbs delete "no-such-backup")
expect "delete reports a missing backup" jqt "$out" '.ok == false and .msg == "missing"'
out=$(fbs delete "$name")
expect "delete removes the backup" jqt "$out" '.ok == true'
expect "deleted folder is gone" test ! -e "$dir"
out=$(fbs backups)
expect "two backups left" jqt "$out" '.items | length == 2'

# ---- reboot
rm -f "$R/reboot.log"
fbs reboot bootloader > /dev/null
Expand Down
3 changes: 2 additions & 1 deletion tests/webui-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ for lang in en ar; do
check "super card filled" 'system_a'
check "backup sets described" 'id="setCritical">[^<]'
check "reboot targets listed" 'data-r="bootloader"'
check "beta badge shown" 'id="betaChip" data-i="beta">'
check "no beta badge on a stable build" 'id="betaChip" hidden'
check "backups can be deleted" 'data-act="delete"'
check "links listed" 'data-url="https://t.me/IFOKNR1"'
check "group link" 'data-url="https://t.me/BeNeXTBrO"'
check "link to the Windows app" 'data-url="https://github.com/ifoknr/FastbootStudio/releases/latest"'
Expand Down
6 changes: 3 additions & 3 deletions update.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "v2.5.0",
"versionCode": 250,
"zipUrl": "https://github.com/ifoknr/FastbootStudio-Companion/releases/download/v2.5.0/FastbootStudio-Companion-v2.5.0.zip",
"version": "v2.5.1",
"versionCode": 251,
"zipUrl": "https://github.com/ifoknr/FastbootStudio-Companion/releases/download/v2.5.1/FastbootStudio-Companion-v2.5.1.zip",
"changelog": "https://raw.githubusercontent.com/ifoknr/FastbootStudio-Companion/main/CHANGELOG.md"
}
Loading