-
Notifications
You must be signed in to change notification settings - Fork 61
Expand file tree
/
Copy pathimagebuilder.sh
More file actions
1333 lines (1150 loc) · 53.5 KB
/
imagebuilder.sh
File metadata and controls
1333 lines (1150 loc) · 53.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/bash
#================================================================================================
# Description: Build OpenWrt with Image Builder
#================================================================================================
# Author: https://github.com/unifreq/openwrt_packit
# https://github.com/ophub/amlogic-s9xxx-openwrt
# https://downloads.openwrt.org/releases
# https://downloads.immortalwrt.org/releases
# https://github.com/rtaserver/RTA-WRT
#
# Command: ./config/imagebuilder/imagebuilder.sh <source:branch> <target>
# Example: ./config/imagebuilder/imagebuilder.sh openwrt:24.10.0 x86-64
# Available Devices
#- s905x | HG680P, B860Hv1/v2
#- s905x2 | HG680FJ, B860Hv5, MNC CYBORG001
#- s905x3 |
#- s905x4 | AKARI AX810, dll
#- s912
#- h5-orangepi-zeroplus2 | Alwiner H5 Orange Pi Zero Plus 2
#- h5-orangepi-zeroplus | Alwiner H5 Orange Pi Zero Plus
#- h5-orangepi-prime | Alwiner H5 Orange Pi Prime
#- h5-orangepi-pc2 | Alwiner H5 Orange Pi PC 2
#- h6-orangepi-lite2 | Alwiner H6 Orange Pi Lite 2
#- h6-orangepi-1plus | Alwiner H6 Orange Pi 1 Plus
#- h6-orangepi-3 | Alwiner H6 Orange Pi 3
#- h6-orangepi-3lts | Alwiner H6 Orange Pi 3 LTS
#- h616-orangepi-zero2 | Alwiner H616 Orange Pi Zero 2
#- h618-orangepi-zero2w | Alwiner H618 Orange Pi Zero 2W
#- h618-orangepi-zero3 | Alwiner H618 Orange Pi Zero 3
#- rk3566-orangepi-3b | Rockchip RK3566 Orange Pi 3B
#- rk3588-orangepi-5plus | Rockchip RK3588 Orange Pi 5 Plus
#- rk3588s-orangepi-5 | Rockchip RK3588S Orange Pi 5
#- bcm2710 | Raspberry Pi 3A+/3B/3B+/CM3/Zero2/Zero2W (64bit)
#- bcm2711 | Raspberry Pi 4B/400 (64bit)
#- x86-64 | x86 64bit
#================================================================================================
# Default parameters
make_path="${PWD}/scripts"
openwrt_dir="imagebuilder"
imagebuilder_path="${make_path}/${openwrt_dir}"
custom_files_path="${make_path}/files"
custom_packages_path="${make_path}/packages"
# Output log prefixes with better color handling and backup if tput fails
setup_colors() {
PURPLE="\033[95m"
BLUE="\033[94m"
GREEN="\033[92m"
YELLOW="\033[93m"
RED="\033[91m"
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
RESET="\033[0m"
STEPS="[${PURPLE} STEPS ${RESET}]"
INFO="[${BLUE} INFO ${RESET}]"
SUCCESS="[${GREEN} SUCCESS ${RESET}]"
WARNING="[${YELLOW} WARNING ${RESET}]"
ERROR="[${RED} ERROR ${RESET}]"
# Formatting
CL=$(echo "\033[m")
UL=$(echo "\033[4m")
BOLD=$(echo "\033[1m")
BFR="\\r\\033[K"
HOLD=" "
TAB=" "
}
spinner() {
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local colors=("\033[31m" "\033[33m" "\033[32m" "\033[36m" "\033[34m" "\033[35m" "\033[91m" "\033[92m" "\033[93m" "\033[94m")
local spin_i=0
local color_i=0
local interval=0.1
printf "\e[?25l"
while true; do
local color="${colors[color_i]}"
printf "\r ${color}%s${CL}" "${frames[spin_i]}"
spin_i=$(( (spin_i + 1) % ${#frames[@]} ))
color_i=$(( (color_i + 1) % ${#colors[@]} ))
sleep "$interval"
done
}
setup_colors
format_time() {
local total_seconds=$1
local hours=$((total_seconds / 3600))
local minutes=$(( (total_seconds % 3600) / 60 ))
local seconds=$((total_seconds % 60))
printf "%02d:%02d:%02d" $hours $minutes $seconds
}
cmdinstall() {
local cmd="$1"
local desc="${2:-$cmd}"
echo -ne "${TAB}${HOLD}${INFO} ${desc}${HOLD}"
spinner &
SPINNER_PID=$!
local start_time=$(date +%s)
local output=$($cmd 2>&1)
local exit_code=$?
local end_time=$(date +%s)
local elapsed_time=$((end_time - start_time))
local formatted_time=$(format_time $elapsed_time)
if [ $exit_code -eq 0 ]; then
if [ -n "$SPINNER_PID" ] && ps | grep $SPINNER_PID > /dev/null; then kill $SPINNER_PID > /dev/null; fi
printf "\e[?25h"
echo -e "${BFR}${SUCCESS} ${desc} ${BLUE}[$formatted_time]${RESET}"
else
if [ -n "$SPINNER_PID" ] && ps | grep $SPINNER_PID > /dev/null; then kill $SPINNER_PID > /dev/null; fi
printf "\e[?25h"
echo -e "${BFR}${ERROR} ${desc} ${BLUE}[$formatted_time]${RESET}"
echo "$output"
exit 1
fi
}
#================================================================================================
# Handle errors and exit
error_msg() {
local line_number=${2:-${BASH_LINENO[0]}}
echo -e "${ERROR} ${1} (Line: ${line_number})" >&2
echo "Call stack:" >&2
local frame=0
while caller $frame; do
((frame++))
done >&2
exit 1
}
# Check And Install Required Dependencies
check_dependencies() {
local dependencies=("aria2" "curl" "tar" "gzip" "unzip" "git" "wget" "sed" "grep")
echo -e "${STEPS} Checking and installing required dependencies..."
echo -e "${INFO} Updating package lists..."
sudo apt update -qq &> /dev/null 2>&1
for pkg in "${dependencies[@]}"; do
if sudo dpkg -s "$pkg" &> /dev/null 2>&1; then
echo -e "${SUCCESS} ✓ $pkg is already installed"
else
echo -e "${INFO} Installing $pkg..."
if sudo apt-get install -y "$pkg" &> /dev/null 2>&1; then
echo -e "${SUCCESS} ✓ $pkg installed successfully"
else
echo -e "${ERROR} ✗ Failed to install $pkg"
exit 1
fi
fi
done
echo -e "${SUCCESS} Dependencies installation complete!"
}
# Aria2 Download Function
ariadl() {
if [ "$#" -lt 1 ]; then
echo -e "${ERROR} Usage: ariadl <URL> [OUTPUT_FILE]"
return 1
fi
echo -e "${STEPS} Aria2 Downloader"
local URL OUTPUT_FILE OUTPUT_DIR OUTPUT
URL=$1
local RETRY_COUNT=0
local MAX_RETRIES=3
if [ "$#" -eq 1 ]; then
OUTPUT_FILE=$(basename "$URL")
OUTPUT_DIR="."
else
OUTPUT=$2
OUTPUT_DIR=$(dirname "$OUTPUT")
OUTPUT_FILE=$(basename "$OUTPUT")
fi
if [ ! -d "$OUTPUT_DIR" ]; then
mkdir -p "$OUTPUT_DIR"
fi
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
echo -e "${INFO} Downloading: $URL (Attempt $((RETRY_COUNT + 1))/$MAX_RETRIES)"
if [ -f "$OUTPUT_DIR/$OUTPUT_FILE" ]; then
rm "$OUTPUT_DIR/$OUTPUT_FILE"
fi
aria2c -q -d "$OUTPUT_DIR" -o "$OUTPUT_FILE" "$URL"
if [ $? -eq 0 ]; then
echo -e "${SUCCESS} Downloaded: $OUTPUT_FILE"
return 0
else
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then
echo -e "${ERROR} Download failed. Retrying..."
sleep 2
fi
fi
done
echo -e "${ERROR} Failed to download: $OUTPUT_FILE after $MAX_RETRIES attempts"
return 1
}
# Download external packages
download_packages() {
local list=("${!2}") # Capture array argument
if [[ $1 == "github" ]]; then
for entry in "${list[@]}"; do
IFS="|" read -r filename base_url <<< "$entry"
local file_urls=$(curl -s "$base_url" | grep "browser_download_url" | grep -oE "https.*/${filename}_[_0-9a-zA-Z\._~-]*\.ipk" | sort -V | tail -n 1)
if [ -z "$file_urls" ]; then
error_msg "Failed to retrieve package info for [$filename] from $base_url"
continue
fi
for file_url in $file_urls; do
if [ -n "$file_url" ]; then
ariadl "$file_url" "$(basename "$file_url")"
fi
done
done
elif [[ $1 == "custom" ]]; then
for entry in "${list[@]}"; do
IFS="|" read -r filename base_url <<< "$entry"
# Array untuk menyimpan pola pencarian
local search_patterns=(
"\"${filename}[^\"]*\.ipk\""
"\"${filename}[^\"]*\.apk\""
"${filename}_.*\.ipk"
"${filename}_.*\.apk"
"${filename}.*\.ipk"
"${filename}.*\.apk"
)
local file_urls=""
local full_url=""
# Coba berbagai pola pencarian
for pattern in "${search_patterns[@]}"; do
file_urls=$(curl -sL "$base_url" | grep -oE "$pattern" | sed 's/"//g' | sort -V | tail -n 1)
if [ -n "$file_urls" ]; then
full_url="${base_url}/${file_urls%%\"*}"
break
fi
done
if [ -n "$full_url" ]; then
ariadl "$full_url" "${filename}.ipk"
else
error_msg "No matching file found for [$filename] at $base_url"
fi
done
fi
}
# Downloading OpenWrt ImageBuilder
download_imagebuilder() {
cd "${make_path}" || { error_msg "Failed to change directory to ${make_path}"; }
echo -e "${STEPS} Start downloading OpenWrt files..."
# Determine target and architecture based on device
case "${op_devices}" in
h5-*|h616-*|h618-*|h6-*) # Allwinner (H5/H616/H618/H6)
op_target="allwinner"
target_profile="generic"
target_system="armsr/armv8"
target_name="armsr-armv8"
ARCH_1="arm64"
ARCH_2="aarch64"
ARCH_3="aarch64_generic"
KERNEL="6.1.104-AW64-DBAI"
KERNEL2="6.1.31-AW64-DBAI"
KERNEL3="6.6.6-AW64-DBAI"
;;
s905*) # Amlogic (S905*)
op_target="amlogic"
target_profile="generic"
target_system="armsr/armv8"
target_name="armsr-armv8"
ARCH_1="arm64"
ARCH_2="aarch64"
ARCH_3="aarch64_generic"
KERNEL="6.1.66-DBAI"
KERNEL2="5.15.y_6.6.y"
;;
s912) # Amlogic (S912)
op_target="amlogic"
target_profile="generic"
target_system="armsr/armv8"
target_name="armsr-armv8"
ARCH_1="arm64"
ARCH_2="aarch64"
ARCH_3="aarch64_generic"
KERNEL=""
KERNEL2="5.15.y_6.6.y"
;;
rk*) # Rockchip (RK*)
op_target="rockchip"
target_profile="generic"
target_system="armsr/armv8"
target_name="armsr-armv8"
ARCH_1="arm64"
ARCH_2="aarch64"
ARCH_3="aarch64_generic"
KERNEL="5.10.160-rk35v-dbai"
KERNEL2="5.15.y_6.6.y"
;;
bcm2710*) # Raspberry Pi 3A+/3B/3B+/CM3/Zero2/Zero2W (64bit)
op_target="bcm2710"
target_profile="rpi-3"
target_system="bcm27xx/bcm2710"
target_name="bcm27xx-bcm2710"
ARCH_1="arm64"
ARCH_2="aarch64"
ARCH_3="aarch64_cortex-a53"
;;
bcm2711*) # Raspberry Pi 4B/400 (64bit)
op_target="bcm2711"
target_profile="rpi-4"
target_system="bcm27xx/bcm2711"
target_name="bcm27xx-bcm2711"
ARCH_1="arm64"
ARCH_2="aarch64"
ARCH_3="aarch64_cortex-a72"
;;
x86-64|x86_64) # (x86_64)
op_target="x86-64"
target_profile="generic"
target_system="x86/64"
target_name="x86-64"
ARCH_1="amd64"
ARCH_2="x86_64"
ARCH_3="x86_64"
;;
*)
echo -e "${INFO} Available target devices: h5-*, h616-*, h618-*, h6-*, s905*, rk*, x86-64"
error_msg "Unknown target: ${op_devices}"
;;
esac
CURVER=$(echo "${op_branch}" | awk -F. '{print $1"."$2}')
if [[ ${CURVER} == "24.10" ]]; then
archive_ext="tar.zst"
elif [[ ${CURVER} == "23.05" ]]; then
archive_ext="tar.xz"
fi
download_file="https://downloads.${op_sourse}.org/releases/${op_branch}/targets/${target_system}/${op_sourse}-imagebuilder-${op_branch}-${target_name}.Linux-x86_64.${archive_ext}"
ariadl "${download_file}" "${op_sourse}-imagebuilder-${op_branch}-${target_name}.Linux-x86_64.${archive_ext}"
# Extract downloaded archive
echo -e "${INFO} Extracting archive..."
case "${archive_ext}" in
tar.xz)
tar -xJf *-imagebuilder-* > /dev/null 2>&1 || error_msg "Failed to extract tar.xz archive."
;;
tar.zst)
tar -xvf *-imagebuilder-* > /dev/null 2>&1 || error_msg "Failed to extract tar.zst archive."
;;
*)
error_msg "Unknown archive extension: ${archive_ext}"
;;
esac
# Move extracted files to the appropriate directory
rm -f *-imagebuilder-*.${archive_ext}
mv -f *-imagebuilder-* "${openwrt_dir}" || error_msg "Failed to move extracted files to ${openwrt_dir}."
# Finalize and verify
sync && sleep 3
echo -e "${SUCCESS} OpenWrt ImageBuilder downloaded and extracted successfully."
}
# Adjust related files in the ImageBuilder directory
adjust_settings() {
cd "${imagebuilder_path}" || { error_msg "Failed to change directory to ${imagebuilder_path}"; }
echo -e "${STEPS} Start adjusting .config file and related settings..."
# Variables
DTM=$(date '+%d-%m-%Y')
CURVER=$(echo "${op_branch}" | awk -F. '{print $1"."$2}')
# Update 99-first-setup
FIRST_SETUP_FILE="${custom_files_path}/etc/uci-defaults/99-first-setup"
if [[ -s "${FIRST_SETUP_FILE}" ]]; then
sed -i "s|Ouc3kNF6|$DTM|g" "${FIRST_SETUP_FILE}"
echo -e "${INFO} Updated 99-first-setup with date: $DTM"
else
echo -e "${WARN} File 99-first-setup not found or is empty at: ${FIRST_SETUP_FILE}"
fi
# Update repositories.conf
REPO_CONF="repositories.conf"
if [[ -s "${REPO_CONF}" ]]; then
sed -i '\|option check_signature| s|^|#|' "${REPO_CONF}"
echo -e "${INFO} Updated repositories.conf to disable signature checks."
else
echo -e "${WARN} File repositories.conf not found or is empty."
fi
# Update Makefile
MAKEFILE="Makefile"
if [[ -s "${MAKEFILE}" ]]; then
sed -i "s/install \$(BUILD_PACKAGES)/install \$(BUILD_PACKAGES) --force-overwrite --force-downgrade/" "${MAKEFILE}"
echo -e "${INFO} Updated Makefile to include force-overwrite and force-downgrade."
else
echo -e "${WARN} File Makefile not found or is empty."
fi
# Update .config
CONFIG_FILE=".config"
if [[ -s "${CONFIG_FILE}" ]]; then
echo -e "${INFO} Updating .config file settings..."
# Resize Boot and Rootfs partition sizes
sed -i "s/CONFIG_TARGET_KERNEL_PARTSIZE=.*/CONFIG_TARGET_KERNEL_PARTSIZE=128/" "${CONFIG_FILE}"
if [[ "$op_fiturs" == "full-fitur" ]]; then
sed -i "s/CONFIG_TARGET_ROOTFS_PARTSIZE=.*/CONFIG_TARGET_ROOTFS_PARTSIZE=2048/" "${CONFIG_FILE}"
elif [[ "$op_fiturs" == "simpel" ]]; then
sed -i "s/CONFIG_TARGET_ROOTFS_PARTSIZE=.*/CONFIG_TARGET_ROOTFS_PARTSIZE=1024/" "${CONFIG_FILE}"
fi
# Amlogic-specific settings
case "${op_target}" in
amlogic|allwinner|rockchip)
sed -i "s/CONFIG_TARGET_ROOTFS_CPIOGZ=.*/# CONFIG_TARGET_ROOTFS_CPIOGZ is not set/" "${CONFIG_FILE}"
sed -i "s/CONFIG_TARGET_ROOTFS_EXT4FS=.*/# CONFIG_TARGET_ROOTFS_EXT4FS is not set/" "${CONFIG_FILE}"
sed -i "s/CONFIG_TARGET_ROOTFS_SQUASHFS=.*/# CONFIG_TARGET_ROOTFS_SQUASHFS is not set/" "${CONFIG_FILE}"
sed -i "s/CONFIG_TARGET_IMAGES_GZIP=.*/# CONFIG_TARGET_IMAGES_GZIP is not set/" "${CONFIG_FILE}"
echo -e "${INFO} Updated Amlogic-specific .config settings."
;;
x86-64)
sed -i "s/CONFIG_ISO_IMAGES=y/# CONFIG_ISO_IMAGES is not set/" "${CONFIG_FILE}"
sed -i "s/CONFIG_VHDX_IMAGES=y/# CONFIG_VHDX_IMAGES is not set/" "${CONFIG_FILE}"
echo -e "${INFO} Updated x86_64-specific .config settings."
;;
esac
else
error_msg "No .config file found in ${imagebuilder_path}. Ensure the correct file is available."
fi
# Final synchronization and directory status check
sync && sleep 3
echo -e "${SUCCESS} Adjusted .config file and related settings successfully."
}
# Add custom packages
# If there is a custom package or ipk you would prefer to use create a [ packages ] directory,
# If one does not exist and place your custom ipk within this directory.
custom_packages() {
cd "${imagebuilder_path}" || { error_msg "Failed to change directory to ${imagebuilder_path}"; }
echo -e "${STEPS} Start adding custom packages..."
# Create the [packages] directory if not exists
[[ -d "packages" ]] || mkdir -p "packages"
if [[ -d "${custom_packages_path}" ]]; then
# Copy custom packages
cp -rf "${custom_packages_path}/"* "packages/" > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo -e "${SUCCESS} Custom packages successfully copied to the [ packages ] directory."
else
echo -e "${WARNING} Failed to copy packages from ${custom_packages_path} to the [ packages ] directory."
fi
else
echo -e "${WARNING} No customized packages found in ${custom_packages_path}."
fi
cd "packages" || { error_msg "Failed to access [packages] directory."; }
# Handle GitHub-based IPK downloads
declare -a github_packages
if [[ "$op_target" == "amlogic" ]]; then
echo -e "${INFO} Adding luci-app-amlogic for target Amlogic."
github_packages+=("luci-app-amlogic|https://api.github.com/repos/ophub/luci-app-amlogic/releases/latest")
fi
github_packages+=(
"luci-app-alpha-config|https://api.github.com/repos/animegasan/luci-app-alpha-config/releases/latest"
"luci-theme-material3|https://api.github.com/repos/AngelaCooljx/luci-theme-material3/releases/latest"
"luci-app-neko|https://api.github.com/repos/nosignals/openwrt-neko/releases/latest"
)
download_packages "github" github_packages[@]
# Handle other custom package downloads
CURVER=$(echo "${op_branch}" | awk -F. '{print $1"."$2}')
declare -a other_packages=(
"modemmanager-rpcd|https://downloads.$op_sourse.org/releases/packages-24.10/$ARCH_3/packages"
"luci-proto-modemmanager|https://downloads.$op_sourse.org/releases/packages-24.10/$ARCH_3/luci"
"libqmi|https://downloads.$op_sourse.org/releases/packages-24.10/$ARCH_3/packages"
"libmbim|https://downloads.$op_sourse.org/releases/packages-24.10/$ARCH_3/packages"
"modemmanager|https://downloads.$op_sourse.org/releases/packages-24.10/$ARCH_3/packages"
"sms-tool|https://downloads.$op_sourse.org/releases/packages-$CURVER/$ARCH_3/packages"
"tailscale|https://downloads.$op_sourse.org/releases/packages-$CURVER/$ARCH_3/packages"
"python3-speedtest-cli|https://downloads.openwrt.org/releases/packages-$CURVER/$ARCH_3/packages"
"dns2tcp|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/packages"
"luci-app-argon-config|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
"luci-theme-argon|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
"luci-app-openclash|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
"luci-app-passwall|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
"luci-app-tailscale|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"luci-app-diskman|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-zte|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-gosun|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-qmi|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-yuge|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-thales|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-tw|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-meig|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-styx|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-mikrotik|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-dell|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-sierra|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-quectel|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-huawei|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-xmm|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-telit|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-fibocom|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo-serial-simcom|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"modeminfo|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"luci-app-modeminfo|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"atinout|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"luci-app-poweroff|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"xmm-modem|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"luci-app-lite-watchdog|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"luci-theme-alpha|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"luci-app-adguardhome|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"adguardhome|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"luci-app-netspeedtest|https://fantastic-packages.github.io/packages/releases/$CURVER/packages/x86_64/luci"
"sing-box|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"mihomo|https://dl.openwrt.ai/releases/24.10/packages/$ARCH_3/kiddin9"
"luci-app-internet-detector|https://github.com/gSpotx2f/packages-openwrt/raw/refs/heads/master/current"
"internet-detector|https://github.com/gSpotx2f/packages-openwrt/raw/refs/heads/master/current"
"internet-detector-mod-modem-restart|https://github.com/gSpotx2f/packages-openwrt/raw/refs/heads/master/current"
"luci-app-cpu-status-mini|https://github.com/gSpotx2f/packages-openwrt/raw/refs/heads/master/current"
"luci-app-disks-info|https://github.com/gSpotx2f/packages-openwrt/raw/refs/heads/master/current"
"luci-app-log-viewer|https://github.com/gSpotx2f/packages-openwrt/raw/refs/heads/master/current"
"luci-app-temp-status|https://github.com/gSpotx2f/packages-openwrt/raw/refs/heads/master/current"
"luci-app-zerotier|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
"luci-app-ramfree|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
"luci-app-3ginfo-lite|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
"modemband|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/packages"
"luci-app-modemband|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
"luci-app-sms-tool-js|https://downloads.immortalwrt.org/releases/packages-$CURVER/$ARCH_3/luci"
)
download_packages "custom" other_packages[@]
echo -e "${STEPS} Start Clash Core Download !"
if [[ "$ARCH_3" == "x86_64" ]]; then
clash_meta=$(meta_api="https://api.github.com/repos/MetaCubeX/mihomo/releases/latest" && meta_file="mihomo-linux-${ARCH_1}-compatible" && curl -s "${meta_api}" | grep "browser_download_url" | grep -oE "https.*${meta_file}-v[0-9]+\.[0-9]+\.[0-9]+\.gz" | head -n 1)
else
clash_meta=$(meta_api="https://api.github.com/repos/MetaCubeX/mihomo/releases/latest" && meta_file="mihomo-linux-${ARCH_1}" && curl -s "${meta_api}" | grep "browser_download_url" | grep -oE "https.*${meta_file}-v[0-9]+\.[0-9]+\.[0-9]+\.gz" | head -n 1)
fi
# Nikki
nikki_api="https://api.github.com/repos/rizkikotet-dev/OpenWrt-nikki-Mod/releases"
nikki_file_ipk="nikki_${ARCH_3}-openwrt-${CURVER}"
nikki_file_ipk_down=$(curl -s "${nikki_api}" | grep "browser_download_url" | grep -oE "https.*${nikki_file_ipk}.*.tar.gz" | head -n 1)
#passwall
passwall_api="https://api.github.com/repos/xiaorouji/openwrt-passwall/releases"
passwall_file_zip="passwall_packages_ipk_${ARCH_3}"
passwall_file_zip_down=$(curl -s "${passwall_api}" | grep "browser_download_url" | grep -oE "https.*${passwall_file_zip}.*.zip" | head -n 1)
# Output download information
echo -e "${STEPS} Installing OpenClash, Nikki And Passwall"
mkdir -p "${custom_files_path}/etc/openclash/core"
ariadl "${clash_meta}" "${custom_files_path}/etc/openclash/core/clash_meta.gz"
gzip -d "${custom_files_path}/etc/openclash/core/clash_meta.gz" || error_msg "Error: Failed to extract OpenClash package."
ariadl "${nikki_file_ipk_down}" "${nikki_file_ipk}.tar.gz"
tar -xzvf "nikki_${ARCH_3}-openwrt-${CURVER}.tar.gz" > /dev/null 2>&1 && rm "nikki_${ARCH_3}-openwrt-${CURVER}.tar.gz" || error_msg "Error: Failed to extract Nikki package."
ariadl "${passwall_file_zip_down}" "passwall_packages_ipk_${ARCH_3}.zip"
unzip -q "passwall_packages_ipk_${ARCH_3}.zip" && rm "passwall_packages_ipk_${ARCH_3}.zip" || error_msg "Error: Failed to extract Passwall package."
# Sync and provide directory status
sync && sleep 3
echo -e "${SUCCESS} All custom packages successfully downloaded and extracted."
}
# Add custom packages, lib, theme, app and i18n, etc.
custom_config() {
cd "${imagebuilder_path}" || { error_msg "Failed to change directory to ${imagebuilder_path}"; }
echo -e "${STEPS} Start adding custom config..."
# Define URLs for custom scripts
declare -A custom_scripts=(
["${custom_files_path}/sbin/sync_time.sh"]="https://raw.githubusercontent.com/frizkyiman/auto-sync-time/main/sbin/sync_time.sh"
["${custom_files_path}/usr/bin/clock"]="https://raw.githubusercontent.com/frizkyiman/auto-sync-time/main/usr/bin/clock"
["${custom_files_path}/usr/bin/mount_hdd"]="https://raw.githubusercontent.com/frizkyiman/auto-mount-hdd/main/mount_hdd"
)
echo -e "${INFO} Downloading custom scripts..."
for file_path in "${!custom_scripts[@]}"; do
file_url="${custom_scripts[$file_path]}"
target_dir=$(dirname "$file_path")
# Ensure target directory exists
mkdir -p "$target_dir" || { echo -e "${ERROR} Failed to create directory $target_dir"; continue; }
# Download the script
ariadl "$file_url" "$file_path"
done
# Add custom config files
if [[ "$op_fiturs" == "full-fitur" ]]; then
echo -e "${INFO} No custom config added."
elif [[ "$op_fiturs" == "simpel" ]]; then
echo -e "${INFO} No custom config added."
fi
# Sync and provide directory status
sync && sleep 3
echo -e "${SUCCESS} All custom configuration setup completed!"
}
# Add custom files
# The FILES variable allows custom configuration files to be included in images built with Image Builder.
# The [ files ] directory should be placed in the Image Builder root directory where you issue the make command.
custom_files() {
cd "${imagebuilder_path}" || { error_msg "Failed to change directory to ${imagebuilder_path}"; }
echo -e "${STEPS} Start adding custom files..."
if [[ -d "${custom_files_path}" ]]; then
# Ensure the [ files ] directory exists
[[ -d "files" ]] || mkdir -p "files"
# Copy custom files
cp -rf "${custom_files_path}/"* "files"
if [[ $? -eq 0 ]]; then
echo -e "${SUCCESS} Custom files successfully copied to the [ files ] directory."
else
error_msg "Failed to copy files from ${custom_files_path} to the [ files ] directory."
fi
else
echo -e "${WARNING} No customized files were found in ${custom_files_path}."
fi
# Sync and provide directory status
sync && sleep 3
echo -e "${SUCCESS} All custom files successfully added."
}
# Rebuild OpenWrt firmware
rebuild_firmware() {
set -e # Hentikan eksekusi jika terjadi kesalahan
echo -e "${STEPS} Start building OpenWrt with Image Builder..."
# Validasi variabel penting
if [[ -z ${imagebuilder_path} || -z ${op_sourse} || -z ${op_target} || -z ${target_profile} ]]; then
error_msg "Error: Required variables are not set. Exiting..."
fi
# Masuk ke direktori Image Builder
cd "${imagebuilder_path}" || { error_msg "Error: Unable to access ${imagebuilder_path}"; }
# Membersihkan build lama
make clean > /dev/null 2>&1 || { error_msg "Error: Failed to clean previous build"; }
mkdir -p ${imagebuilder_path}/out_firmware ${imagebuilder_path}/out_rootfs
# Selecting default packages, lib, app and etc.
# Profile info
make info
# Main configuration name
PROFILE=""
PACKAGES=""
# Default
PACKAGES+=" -dnsmasq dnsmasq-full cgi-io libiwinfo libiwinfo-data libiwinfo-lua liblua \
luci-base luci-lib-base luci-lib-ip luci-lib-jsonc luci-lib-nixio luci-mod-admin-full \
luci-app-temp-status cpusage ttyd dmesg kmod-tun luci-lib-ipkg \
zram-swap adb parted losetup resize2fs luci luci-ssl block-mount htop bash curl wget-ssl \
tar unzip unrar gzip jq luci-app-ttyd nano httping screen openssh-sftp-server \
liblucihttp liblucihttp-lua libubus-lua lua luci-app-firewall luci-app-opkg \
ca-bundle ca-certificates luci-compat coreutils-sleep fontconfig coreutils-whoami file lolcat \
luci-base luci-lib-base luci-lib-ip luci-lib-jsonc luci-lib-nixio luci-mod-admin-full \
luci-mod-network luci-mod-status luci-mod-system luci-proto-ipv6 luci-proto-ppp \
luci-theme-bootstrap px5g-wolfssl rpcd rpcd-mod-file rpcd-mod-iwinfo rpcd-mod-luci \
rpcd-mod-rrdns uhttpd uhttpd-mod-ubus coreutils coreutils-base64 coreutils-nohup coreutils-stty libc coreutils-stat\
ip-full libuci-lua microsocks resolveip tcping ipset ipt2socks iptables iptables-legacy \
iptables-mod-iprange iptables-mod-socket iptables-mod-tproxy kmod-ipt-nat luci-lua-runtime zoneinfo-asia zoneinfo-core \
perl perlbase-base perlbase-bytes perlbase-class perlbase-config perlbase-cwd perlbase-dynaloader perlbase-errno perlbase-essential perlbase-fcntl perlbase-file \
perlbase-filehandle perlbase-i18n perlbase-integer perlbase-io perlbase-list perlbase-locale perlbase-params perlbase-posix \
perlbase-re perlbase-scalar perlbase-selectsaver perlbase-socket perlbase-symbol perlbase-tie perlbase-time perlbase-unicore perlbase-utf8 perlbase-xsloader"
# Modem and UsbLAN Driver
PACKAGES+=" kmod-usb-net-rtl8150 kmod-usb-net-rtl8152 kmod-usb-net-asix kmod-usb-net-asix-ax88179"
PACKAGES+=" kmod-mii kmod-usb-net kmod-usb-wdm kmod-usb-net-qmi-wwan uqmi luci-proto-qmi \
kmod-usb-net-cdc-ether kmod-usb-serial-option kmod-usb-serial kmod-usb-serial-wwan qmi-utils \
kmod-usb-serial-qualcomm kmod-usb-acm kmod-usb-net-cdc-ncm kmod-usb-net-cdc-mbim umbim \
modemmanager modemmanager-rpcd luci-proto-modemmanager libmbim libqmi usbutils luci-proto-mbim luci-proto-ncm \
kmod-usb-net-huawei-cdc-ncm kmod-usb-net-cdc-ether kmod-usb-net-rndis kmod-usb-net-sierrawireless kmod-usb-ohci kmod-usb-serial-sierrawireless \
kmod-usb-uhci kmod-usb2 kmod-usb-ehci kmod-usb-net-ipheth usbmuxd libusbmuxd-utils libimobiledevice-utils usb-modeswitch kmod-nls-utf8 mbim-utils xmm-modem \
kmod-phy-broadcom kmod-phylib-broadcom kmod-tg3 libusb-1.0-0"
# Modem Tools
PACKAGES+=" modeminfo-serial-zte modeminfo-serial-gosun modeminfo-qmi modeminfo-serial-yuge modeminfo-serial-thales modeminfo-serial-tw modeminfo-serial-meig modeminfo-serial-styx modeminfo-serial-mikrotik modeminfo-serial-dell modeminfo-serial-sierra modeminfo-serial-quectel modeminfo-serial-huawei modeminfo-serial-xmm modeminfo-serial-telit modeminfo-serial-fibocom modeminfo-serial-simcom modeminfo luci-app-modeminfo"
PACKAGES+=" atinout modemband luci-app-modemband sms-tool luci-app-sms-tool-js luci-app-lite-watchdog luci-app-3ginfo-lite picocom minicom"
# Tunnel option
OPENCLASH+="coreutils-nohup bash dnsmasq-full curl ca-certificates ipset ip-full libcap libcap-bin ruby ruby-yaml kmod-tun kmod-inet-diag unzip kmod-nft-tproxy luci-compat luci luci-base luci-app-openclash"
MIHOMO+="nikki luci-app-nikki"
PASSWALL+="chinadns-ng resolveip dns2socks dns2tcp ipt2socks microsocks tcping xray-core xray-plugin luci-app-passwall"
NEKOCLASH+="kmod-tun bash curl jq mihomo sing-box php8 php8-mod-curl luci-app-neko"
# Remote Services
PACKAGES+=" luci-app-zerotier luci-app-cloudflared tailscale luci-app-tailscale"
# NAS and Hard disk tools
PACKAGES+=" luci-app-diskman luci-app-disks-info smartmontools kmod-usb-storage kmod-usb-storage-uas ntfs-3g"
# Bandwidth And Network Monitoring
PACKAGES+=" internet-detector luci-app-internet-detector internet-detector-mod-modem-restart nlbwmon luci-app-nlbwmon vnstat2 vnstati2 luci-app-vnstat2 netdata"
# Theme
PACKAGES+=" luci-theme-material luci-theme-argon luci-app-argon-config"
# PHP8
PACKAGES+=" php8 php8-fastcgi php8-fpm php8-mod-session php8-mod-ctype php8-mod-fileinfo php8-mod-zip php8-mod-iconv php8-mod-mbstring"
# More
PACKAGES+=" luci-app-poweroff luci-app-log-viewer luci-app-ramfree"
if [[ "$op_fiturs" == "full-fitur" ]]; then
# Python3
PACKAGES+=" python3 python3-pip"
# AdguardHome
PACKAGES+=" adguardhome luci-app-adguardhome"
# Tunnel
PACKAGES+=" $OPENCLASH $MIHOMO $PASSWALL $NEKOCLASH"
# Docker
PACKAGES+=" docker docker-compose dockerd luci-app-dockerman"
# Speedtest
PACKAGES+=" librespeed-go python3-speedtest-cli iperf3-ssl luci-app-netspeedtest"
# Disable service
DISABLED_SERVICES+=" AdGuardHome"
elif [[ "$op_fiturs" == "simpel" ]]; then
# Tunnel
PACKAGES+=" $OPENCLASH $MIHOMO $PASSWALL"
# Disable service
DISABLED_SERVICES+=""
fi
# Misc and some custom .ipk files
# Exclude package (must use - before packages name)
EXCLUDED+=" -libgd"
MISC=""
case "${op_sourse}" in
openwrt)
MISC+=" luci-app-temp-status luci-app-cpu-status-mini"
EXCLUDED+=" -dnsmasq"
;;
immortalwrt)
MISC+=" "
EXCLUDED+=" -dnsmasq -automount -libustream-openssl -default-settings-chn -luci-i18n-base-zh-cn"
if [ "$ARCH_2" == "x86_64" ]; then
EXCLUDED+=" -kmod-usb-net-rtl8152-vendor"
fi
;;
esac
case "${op_target}" in
amlogic)
MISC+=" luci-app-amlogic ath9k-htc-firmware btrfs-progs hostapd hostapd-utils kmod-ath kmod-ath9k kmod-ath9k-common kmod-ath9k-htc kmod-cfg80211 kmod-crypto-acompress kmod-crypto-crc32c kmod kmod-fs-btrfs kmod-mac80211 wireless-tools wpa-cli wpa-supplicant"
EXCLUDED+=" -procd-ujail"
;;
bcm27*)
MISC+=" kmod-i2c-bcm2835 i2c-tools kmod-i2c-core kmod-i2c-gpio"
EXCLUDED+=" -hostapd -hostapd-common -hostapd-utils"
;;
x86-64)
MISC+=" kmod-iwlwifi iw-full pciutils"
;;
esac
PACKAGES+=" $MISC"
# Membuat image firmware dan menampilkan progress bar
make image PROFILE="${target_profile}" PACKAGES="${PACKAGES} ${EXCLUDED}" FILES="files" DISABLED_SERVICES="$DISABLED_SERVICES"
if [[ $? -eq 0 ]]; then
echo -e "${SUCCESS} Firmware build completed."
for file in ${imagebuilder_path}/bin/targets/*/*/*.img.gz; do
[[ -e "$file" ]] || continue
mv -f "$file" "${imagebuilder_path}/out_firmware"
echo -e "${SUCCESS} Firmware successfully created: $file"
done
for file in ${imagebuilder_path}/bin/targets/*/*/*rootfs.tar.gz; do
[[ -e "$file" ]] || continue
if [[ "${op_target}" == "x86-64" ]]; then
mv -f "$file" "${imagebuilder_path}/out_firmware"
else
mv -f "$file" "${imagebuilder_path}/out_rootfs"
fi
echo -e "${SUCCESS} Rootfs successfully created: $file"
done
sync && sleep 3
echo -e "${SUCCESS} Build completed successfully."
else
error_msg "Error: OpenWrt build failed. Check logs for details."
fi
}
repackwrt() {
# Parse arguments
local builder_type=""
local target_board=""
local target_kernel=""
while [[ $# -gt 0 ]]; do
case "$1" in
--ophub|--ulo)
builder_type="$1"
shift
;;
-t|--target)
target_board="$2"
shift 2
;;
-k|--kernel)
target_kernel="$2"
shift 2
;;
*)
error_msg "Unknown option: $1"
;;
esac
done
# Validate required parameters
if [[ -z "$builder_type" ]]; then
error_msg "Builder type (--ophub or --ulo) is required"
fi
if [[ -z "$target_board" ]]; then
error_msg "Target board (-t) is required"
fi
if [[ -z "$target_kernel" ]]; then
error_msg "Target kernel (-k) is required"
fi
local readonly OPHUB_REPO="https://github.com/ophub/amlogic-s9xxx-openwrt/archive/refs/heads/main.zip"
local readonly ULO_REPO="https://github.com/armarchindo/ULO-Builder/archive/refs/heads/main.zip"
local readonly REQUIRED_SPACE_MB=2048
# Validate required variables
local readonly REQUIRED_VARS=("imagebuilder_path" "op_sourse" "op_branch" "op_devices")
for var in "${REQUIRED_VARS[@]}"; do
if [[ -z "${!var}" ]]; then
error_msg "Required variable '${var}' is not set"
fi
done
# Check available disk space
local available_space
available_space=$(df -m "${imagebuilder_path}" | awk 'NR==2 {print $4}')
if [[ ${available_space} -lt ${REQUIRED_SPACE_MB} ]]; then
error_msg "Insufficient disk space. Required: ${REQUIRED_SPACE_MB}MB, Available: ${available_space}MB"
fi
# Create working directory structure
local readonly work_dir="${imagebuilder_path}"
local builder_dir output_dir repo_url
if [[ "$builder_type" == "--ophub" ]]; then
builder_dir="${work_dir}/amlogic-s9xxx-openwrt-main"
repo_url="${OPHUB_REPO}"
echo -e "${STEPS} Starting firmware repackaging with Ophub..."
else
builder_dir="${work_dir}/ULO-Builder-main"
repo_url="${ULO_REPO}"
echo -e "${STEPS} Starting firmware repackaging with UloBuilder..."
fi
output_dir="${work_dir}/out_firmware"
# Navigate to working directory
if ! cd "${work_dir}"; then
error_msg "Failed to access working directory: ${work_dir}"
fi
# Download and extract builder
ariadl "${repo_url}" "main.zip"
if ! unzip -q main.zip; then
error_msg "Failed to extract builder archive"
rm -f main.zip
fi
rm -f main.zip
# Prepare builder directory
if [[ "$builder_type" == "--ophub" ]]; then
mkdir -p "${builder_dir}/openwrt-armvirt"
else
mkdir -p "${builder_dir}/rootfs"
fi
# Validate and copy rootfs
local readonly rootfs_file="${work_dir}/out_rootfs/${op_sourse}-${op_branch}-armsr-armv8-generic-rootfs.tar.gz"
if [[ ! -f "${rootfs_file}" ]]; then
error_msg "Rootfs file not found: ${rootfs_file}"
fi
echo -e "${INFO} Copying rootfs file..."
if [[ "$builder_type" == "--ophub" ]]; then
if ! cp -f "${rootfs_file}" "${builder_dir}/openwrt-armvirt/"; then
error_msg "Failed to copy rootfs file"
fi
else
if ! cp -f "${rootfs_file}" "${builder_dir}/rootfs/"; then
error_msg "Failed to copy rootfs file"
fi
fi
# Change to builder directory
if ! cd "${builder_dir}"; then
error_msg "Failed to access builder directory: ${builder_dir}"
fi
# Run builder-specific operations
if [[ "$builder_type" == "--ophub" ]]; then
echo -e "${INFO} Running OphubBuilder..."
if ! sudo ./remake -b "${target_board}" -k "${target_kernel}" -s 1024; then
error_msg "OphubBuilder execution failed"
fi
device_output_dir="./openwrt/out"
else
# Apply ULO patches
echo -e "${INFO} Applying UloBuilder patches..."
if [[ -f "./.github/workflows/ULO_Workflow.patch" ]]; then
mv ./.github/workflows/ULO_Workflow.patch ./ULO_Workflow.patch
if ! patch -p1 < ./ULO_Workflow.patch >/dev/null 2>&1; then
echo -e "${WARN} Failed to apply UloBuilder patch"
else
echo -e "${SUCCESS} UloBuilder patch applied successfully"
fi
else
echo -e "${WARN} UloBuilder patch not found"
fi
# Run UloBuilder
echo -e "${INFO} Running UloBuilder..."
local readonly rootfs_basename=$(basename "${rootfs_file}")
if ! sudo ./ulo -y -m "${target_board}" -r "${rootfs_basename}" -k "${target_kernel}" -s 1024; then
error_msg "UloBuilder execution failed"
fi
device_output_dir="./out/${target_board}"
fi
# Verify and copy output files
if [[ ! -d "${device_output_dir}" ]]; then
error_msg "Builder output directory not found: ${device_output_dir}"
fi
echo -e "${INFO} Copying firmware files to output directory..."
if ! cp -rf "${device_output_dir}"/* "${output_dir}/"; then
error_msg "Failed to copy firmware files to output directory"
fi
# Verify output files exist
if ! ls "${output_dir}"/* >/dev/null 2>&1; then
error_msg "No firmware files found in output directory"
fi
sync && sleep 3