A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 660 lines 18 kB view raw
1#!/usr/bin/perl 2# __________ __ ___. 3# Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7# \/ \/ \/ \/ \/ 8# $Id$ 9# 10 11use strict; 12use Getopt::Long qw(:config pass_through); # pass_through so not confused by -DTYPE_STUFF 13use IPC::Open2; 14 15my $ROOT=".."; 16my $wpsdir; 17my $verbose; 18my $rbdir=".rockbox"; 19my $tempdir=".rockbox"; 20my $wpslist; 21my $target; 22my $modelname; 23 24# Get options 25GetOptions ( 'r|root=s' => \$ROOT, 26 'm|modelname=s' => \$modelname, 27 'v|verbose' => \$verbose, 28 'rbdir=s' => \$rbdir, # If we want to put in a different directory 29 'tempdir=s' => \$tempdir, # override .rockbox temporary dir 30 ); 31 32($wpslist, $target) = @ARGV; 33 34my $firmdir="$ROOT/firmware"; 35my $cppdef = $target; 36 37# These parameters are filled in as we parse wpslist 38my $req_t; 39my $theme; 40my $has_wps; 41my $wps; 42my $has_rwps; 43my $rwps; 44my $has_sbs; 45my $sbs; 46my $has_rsbs; 47my $rsbs; 48my $has_fms; 49my $fms; 50my $has_rfms; 51my $rfms; 52my $width; 53my $height; 54my $font; 55my $remotefont; 56my $fgcolor; 57my $bgcolor; 58my $sepcolor; 59my $sep; 60my $statusbar; 61my $remotestatusbar; 62my $author; 63my $backdrop; 64my $lineselectstart; 65my $lineselectend; 66my $selecttype; 67my $iconset; 68my $remoteiconset; 69my $viewericon; 70my $showicons; 71my $remoteviewericon; 72my $lineselecttextcolor; 73my $filetylecolor; 74my $listviewport; 75my $remotelistviewport; 76 77# LCD sizes 78my ($main_height, $main_width, $main_depth); 79my ($remote_height, $remote_width, $remote_depth); 80my $has_remote; 81 82 83if(!$wpslist) { 84 print "Usage: wpsbuilds.pl <WPSLIST> <target>\n", 85 "Run this script in the root of the target build, and it will put all the\n", 86 "stuff in $tempdir/wps/\n and build the cfg according to $rbdir"; 87 exit; 88} 89 90sub getlcdsizes 91{ 92 my ($remote) = @_; 93 my $str; 94 95 if($remote) { 96 # Get the remote LCD screen size 97 $str = <<STOP 98\#include "config.h" 99#ifdef HAVE_REMOTE_LCD 100Height: LCD_REMOTE_HEIGHT 101Width: LCD_REMOTE_WIDTH 102Depth: LCD_REMOTE_DEPTH 103#endif 104STOP 105; 106 } 107 else { 108 $str = <<STOP 109\#include "config.h" 110Height: LCD_HEIGHT 111Width: LCD_WIDTH 112Depth: LCD_DEPTH 113STOP 114; 115 } 116 close(GCC); 117 118 my $cmd = "gcc $cppdef -I. -I$firmdir/export -E -P -"; 119 my $pid = open2(*COUT, *CIN, $cmd) or die "Could not spawn child: $!\n"; 120 121 print CIN $str; 122 close(CIN); 123 waitpid($pid, 0); 124 125 my ($height, $width, $depth, $touch); 126 while(<COUT>) { 127 if($_ =~ /^Height: (\d*)/) { 128 $height = $1; 129 } 130 elsif($_ =~ /^Width: (\d*)/) { 131 $width = $1; 132 } 133 elsif($_ =~ /^Depth: (\d*)/) { 134 $depth = $1; 135 } 136 if($_ =~ /^Touchscreen/) { 137 $touch = 1; 138 } 139 } 140 close(COUT); 141 142 return ($height, $width, $depth); 143} 144 145sub mkdirs 146{ 147 mkdir "$tempdir/wps", 0777; 148 mkdir "$tempdir/themes", 0777; 149 mkdir "$tempdir/icons", 0777; 150 151 if( -d "$tempdir/wps/$theme") { 152 #print STDERR "wpsbuild warning: directory wps/$theme already exists!\n"; 153 } 154 else 155 { 156 mkdir "$tempdir/wps/$theme", 0777; 157 } 158} 159 160sub normalize 161{ 162 my $in = $_[0]; 163 # strip resolution 164 $in =~ s/(\.[0-9]*x[0-9]*x[0-9]*)//; 165 return $in; 166} 167 168sub copybackdrop 169{ 170 #copy the backdrop file into the build dir 171 if ($backdrop ne '') { 172 my $dst = normalize($backdrop); 173 system("cp $ROOT/$backdrop $tempdir/$dst"); 174 } 175} 176 177sub copythemefont 178{ 179 #copy the font specified by the theme 180 my $o = $_[0]; 181 182 $o =~ s/\.fnt/\.bdf/; 183 mkdir "$tempdir/fonts"; 184 system("$ROOT/tools/convbdf -f -o \"$tempdir/fonts/$_[0]\" \"$ROOT/fonts/$o\" "); 185} 186 187sub copythemeicon 188{ 189 my $i = $_[0]; 190 #copy the icon specified by the theme 191 if ($i ne "-") { 192 my $tempicon = $tempdir . "/" . $i; 193 $tempicon =~ /\/.*icons\/(.*)/i; 194 system("cp $ROOT/icons/$1 $tempicon"); 195 } 196} 197 198sub uniq { 199 my %seen = (); 200 my @r = (); 201 foreach my $a (@_) { 202 unless ($seen{$a}) { 203 push @r, $a; 204 $seen{$a} = 1; 205 } 206 } 207 return @r; 208} 209 210sub copywps 211{ 212 # we assume that we copy the WPS files from the same dir the WPSLIST 213 # file is located in 214 my $dir; 215 my %skinfiles = ("wps", $wps, 216 "sbs", $sbs, 217 "fms", $fms, 218 "rwps", $rwps, 219 "rsbs", $rsbs, 220 "rfms", $rfms); 221 my @filelist; 222 my $file; 223 224 if($wpslist =~ /(.*)\/WPSLIST/) { 225 $dir = $1; 226 227 # copy fully-fledged wps, sbs, etc. including graphics 228 foreach my $ext (keys %skinfiles) { 229 next unless ($skinfiles{$ext}); 230 $file = $skinfiles{$ext}; 231 system("cp $dir/$file $tempdir/wps/$theme.$ext"); 232 open(SKIN, "$dir/$file"); 233 while (<SKIN>) { 234 $filelist[$#filelist + 1] = $1 if (/[\(,]([^,]*?.bmp)[\),]/); 235 } 236 close(SKIN); 237 } 238 239 if ($#filelist >= 0) { 240 if (-e "$dir/$theme") { 241 foreach $file (uniq(@filelist)) { 242 system("cp $dir/$theme/$file $tempdir/wps/$theme/"); 243 } 244 } 245 else { 246 print STDERR "beep, no dir to copy WPS from!\n"; 247 } 248 } 249 } else { 250 print STDERR "No source directory!\n"; 251 } 252} 253 254sub buildcfg { 255 my $cfg = $theme . ".cfg"; 256 my @out; 257 258 push @out, <<MOO 259\# 260\# $cfg generated by wpsbuild.pl 261\# $wps is made by $author 262\# 263MOO 264; 265 266 my %skinfiles = ("wps" => $wps, 267 "sbs" => $sbs, 268 "fms" => $fms, 269 "rwps" => $rwps, 270 "rsbs" => $rsbs, 271 "rfms" => $rfms); 272 for my $skin (keys %skinfiles) { 273 my $val = $skinfiles{$skin}; 274 if (!defined($val)) { 275 # dont put value if not defined (e.g. rwps when there's no remote) 276 next; 277 } elsif ($val eq '') { 278 # empty resets to built-in 279 push @out, "$skin: -\n"; 280 } else { 281 # file name is always <theme>.{wps,rwps,...} (see copywps()) 282 push @out, "$skin: $rbdir/wps/$theme.$skin\n"; 283 } 284 } 285 286 push @out, "selector type: $selecttype\n" if (defined($selecttype)); 287 push @out, "backdrop: $backdrop\n" if (defined($backdrop)); 288 push @out, "filetype colours: $filetylecolor\n" if (defined($filetylecolor)); 289 290 if ($main_depth > 2) { 291 push @out, "foreground color: $fgcolor\n" if($fgcolor); 292 push @out, "background color: $bgcolor\n" if($bgcolor); 293 push @out, "line selector start color: $lineselectstart\n" if($lineselectstart); 294 push @out, "line selector end color: $lineselectend\n" if($lineselectend);; 295 push @out, "line selector text color: $lineselecttextcolor\n" if($lineselecttextcolor); 296 # list separator actually depends on HAVE_TOUCSCREEN 297 push @out, "list separator height: $sep\n" if($sep); 298 push @out, "list separator color: $sepcolor\n" if($sepcolor); 299 } 300 301 push @out, "font: $font\n" if (defined($font)); 302 push @out, "statusbar: $statusbar\n" if (defined($statusbar)); 303 push @out, "iconset: $iconset\n" if (defined($iconset)); 304 push @out, "viewers iconset: $viewericon\n" if (defined($viewericon)); 305 push @out, "show icons: $showicons\n" if (defined($viewericon) && defined($showicons)); 306 push @out, "ui viewport: $listviewport\n" if (defined($listviewport)); 307 308 if ($has_remote) { 309 push @out, "remote font: $remotefont\n" if (defined($remotefont)); 310 push @out, "remote statusbar: $remotestatusbar\n" if (defined($remotestatusbar)); 311 push @out, "remote iconset: $remoteiconset\n" if (defined($remoteiconset)); 312 push @out, "remote viewers iconset: $remoteviewericon\n" if (defined($remoteviewericon)); 313 push @out, "remote ui viewport: $remotelistviewport\n" if (defined($remotelistviewport)); 314 } 315 316 if(-f "$tempdir/wps/$cfg") { 317 print STDERR "wpsbuild warning: wps/$cfg already exists!\n"; 318 } 319 else { 320 open(CFG, ">$tempdir/themes/$cfg"); 321 print CFG @out; 322 close(CFG); 323 } 324} 325 326# Get the LCD sizes first 327($main_height, $main_width, $main_depth) = getlcdsizes(); 328($remote_height, $remote_width, $remote_depth) = getlcdsizes(1); 329 330#print "LCD: ${main_width}x${main_height}x${main_depth}\n"; 331$has_remote = 1 if ($remote_height && $remote_width && $remote_depth); 332 333 334# check if line matches the setting string or if it contains a regex 335# that contains the targets resolution 336# 337# the line can be of the from 338# 1) setting: value (handled above) 339# 2) setting.128x96x2: value 340# 3) setting.128x96x2&touchscreen: value 341# The resolution pattern can be a perl-comatible regex 342sub check_res_feature { 343 my ($line, $string, $remote) = @_; 344 if ($line =~ /^$string: *(.*)/i) { 345 return $1; 346 } 347 elsif($line =~ /^$string\.(.*): *(.*)/i) { 348 # $1 is a resolution/feature regex, $2 the filename incl. resolution 349 my $substr = $1; 350 my $fn = $2; 351 my $feature; 352 my $size_str = "${main_width}x${main_height}x${main_depth}"; 353 if ($remote) { 354 $size_str = "${remote_width}x${remote_height}x${remote_depth}"; 355 } 356 357 # extract feature constraint, if any 358 if ($substr =~ /&([a-z0-9_]+)/) { 359 $feature = $1; 360 $substr =~ s/&$feature//; 361 } 362 363 if ($size_str =~ /$substr$/) { 364 if ($feature) { 365 # check feature constrait 366 open(FEAT, "<apps/features"); 367 chomp(my @lines = <FEAT>); 368 close(FEAT); 369 my $matches = (grep { /$feature/ } @lines); 370 return $fn if $matches > 0; 371 } 372 else { 373 # no feature constraint 374 return $fn; 375 } 376 } 377 } 378 return ""; 379} 380 381# check if <theme>.<model>.<ext> exists. If not, check if <theme>.<ext> exists 382sub check_skinfile { 383 my $ext = $_[0]; 384 my $req_skin = $theme . "." . $modelname . ".$ext"; 385 if (-e "$wpsdir/$req_skin") { 386 return $req_skin; 387 } else { 388 $req_skin = $theme . ".$ext"; 389 if (-e "$wpsdir/$req_skin") { 390 return $req_skin; 391 } 392 } 393 return ''; 394} 395 396 397# Infer WPS (etc.) filename from the the if it wasnt given 398$wpslist =~ /(.*)WPSLIST/; 399$wpsdir = $1; 400 401open(WPS, "<$wpslist"); 402while(<WPS>) { 403 my $l = $_; 404 405 # remove CR 406 $l =~ s/\r//g; 407 if($l =~ /^ *\#/) { 408 # skip comment 409 next; 410 } 411 412 # prefix $rbdir with / if needed (needed for the theme.cfg) 413 unless ($rbdir =~ m/^\/.*/) { 414 $rbdir = "/" . $rbdir; 415 } 416 417 if($l =~ /^ *<theme>/i) { 418 # undef is a unary operator (!) 419 undef $theme; 420 undef $has_wps; 421 undef $has_rwps; 422 undef $has_sbs; 423 undef $has_rsbs; 424 undef $has_fms; 425 undef $has_rfms; 426 undef $wps; 427 undef $rwps; 428 undef $sbs; 429 undef $rsbs; 430 undef $fms; 431 undef $rfms; 432 undef $width; 433 undef $height; 434 undef $font; 435 undef $remotefont; 436 undef $fgcolor; 437 undef $bgcolor; 438 undef $sepcolor; 439 undef $sep; 440 undef $statusbar; 441 undef $remotestatusbar; 442 undef $author; 443 undef $backdrop; 444 undef $lineselectstart; 445 undef $lineselectend; 446 undef $selecttype; 447 undef $iconset; 448 undef $remoteiconset; 449 undef $viewericon; 450 undef $showicons; 451 undef $remoteviewericon; 452 undef $lineselecttextcolor; 453 undef $filetylecolor; 454 undef $listviewport; 455 undef $remotelistviewport; 456 } 457 elsif($l =~ /^Name: *(.*)/i) { 458 $theme = $1; 459 } 460 elsif($l =~ /^Authors: *(.*)/i) { 461 $author = $1; 462 } 463 elsif ($l =~ /^WPS: *(yes|no)/i) { 464 $has_wps = $1; 465 } 466 elsif ($l =~ /^RWPS: *(yes|no)/i) { 467 $has_rwps = $1; 468 } 469 elsif ($l =~ /^SBS: *(yes|no)/i) { 470 $has_sbs = $1; 471 } 472 elsif ($l =~ /^RSBS: *(yes|no)/i) { 473 $has_rsbs = $1; 474 } 475 elsif ($l =~ /^FMS: *(yes|no)/i) { 476 $has_fms = $1; 477 } 478 elsif ($l =~ /^RFMS: *(yes|no)/i) { 479 $has_rfms = $1; 480 } 481 elsif($l =~ /^ *<main>/i) { 482 # parse main unit settings 483 while(<WPS>) { 484 my $l = $_; 485 if ($l =~ /^ *<\/main>/i) { 486 last; 487 } 488 elsif($_ = check_res_feature($l, "wps")) { 489 $wps = $_; 490 } 491 elsif($_ = check_res_feature($l, "sbs")) { 492 $sbs = $_; 493 } 494 elsif($_ = check_res_feature($l, "fms")) { 495 $fms = $_; 496 } 497 elsif($_ = check_res_feature($l, "Font")) { 498 $font = $_; 499 } 500 elsif($_ = check_res_feature($l, "Statusbar")) { 501 $statusbar = $_; 502 } 503 elsif($_ = check_res_feature($l, "Backdrop")) { 504 $backdrop = $_; 505 } 506 elsif($l =~ /^Foreground Color: *(.*)/i) { 507 $fgcolor = $1; 508 } 509 elsif($l =~ /^Background Color: *(.*)/i) { 510 $bgcolor = $1; 511 } 512 elsif($_ = check_res_feature($l, "list separator color")) { 513 $sepcolor = $_; 514 } 515 elsif($_ = check_res_feature($l, "list separator height")) { 516 $sep = $_; 517 } 518 elsif($l =~ /^line selector start color: *(.*)/i) { 519 $lineselectstart = $1; 520 } 521 elsif($l =~ /^line selector end color: *(.*)/i) { 522 $lineselectend = $1; 523 } 524 elsif($_ = check_res_feature($l, "selector type")) { 525 $selecttype = $_; 526 } 527 elsif($_ = check_res_feature($l, "iconset")) { 528 $iconset = $_; 529 } 530 elsif($_ = check_res_feature($l, "viewers iconset")) { 531 $viewericon = $_; 532 } 533 elsif($l =~ /^show icons: *(.*)/i) { 534 $showicons = $1; 535 } 536 elsif($l =~ /^line selector text color: *(.*)/i) { 537 $lineselecttextcolor = $1; 538 } 539 elsif($l =~ /^filetype colours: *(.*)/i) { 540 $filetylecolor = $1; 541 } 542 elsif($_ = check_res_feature($l, "ui viewport")) { 543 $listviewport = $_; 544 } 545 } 546 } 547 elsif($l =~ /^ *<remote>/i) { 548 while(<WPS>) { 549 # parse remote settings 550 my $l = $_; 551 if ($l =~ /^ *<\/remote>/i) { 552 last; 553 } 554 elsif(!$has_remote) { 555 next; # dont parse <remote> section 556 } 557 elsif($_ = check_res_feature($l, "rwps", 1)) { 558 $rwps = $_; 559 } 560 elsif($_ = check_res_feature($l, "rsbs", 1)) { 561 $rsbs = $_; 562 } 563 elsif($_ = check_res_feature($l, "rfms", 1)) { 564 $rfms = $_; 565 } 566 elsif($_ = check_res_feature($l, "Font", 1)) { 567 $remotefont = $_; 568 } 569 elsif($_ = check_res_feature($l, "iconset", 1)) { 570 $remoteiconset = $_; 571 } 572 elsif($_ = check_res_feature($l, "viewers iconset", 1)) { 573 $remoteviewericon = $_; 574 } 575 elsif($_ = check_res_feature($l, "statusbar", 1)) { 576 $remotestatusbar = $_; 577 } 578 elsif($_ = check_res_feature($l, "ui viewport", 1)) { 579 $remotelistviewport = $_; 580 } 581 } 582 } 583 elsif($l =~ /^ *<\/theme>/i) { 584 # for each wps,sbs,fms (+ remote variants) check if <theme>[.<model>].wps 585 # exists if no filename was specified in WPSLIST 586 my $req_skin; 587 588 if ($has_wps eq "yes" && !$wps) { 589 $wps = check_skinfile("wps"); 590 } elsif ($has_wps eq "no") { 591 $wps = ''; 592 } 593 594 if ($has_sbs eq "yes" && !$sbs) { 595 $sbs = check_skinfile("sbs"); 596 } elsif ($has_sbs eq "no") { 597 $sbs = ''; 598 } 599 600 if ($has_fms eq "yes" && !$fms) { 601 $fms = check_skinfile("fms"); 602 } elsif ($has_fms eq "no") { 603 $fms = ''; 604 } 605 606 # now check for remote skin files (use main screen's extension) 607 if ($has_remote) { 608 if ($has_rwps eq "yes" && !$rwps) { 609 $rwps = check_skinfile("wps"); 610 } elsif ($has_rwps eq "no") { 611 $rwps = ''; 612 } 613 614 if ($has_rsbs eq "yes" && !$rsbs) { 615 $rsbs = check_skinfile("sbs"); 616 } elsif ($has_rsbs eq "no") { 617 $rsbs = ''; 618 } 619 620 if ($has_rfms eq "yes" && !$rfms) { 621 $rfms = check_skinfile("fms"); 622 } elsif ($has_rfms eq "no") { 623 $rfms = ''; 624 } 625 } 626 #print "LCD: $wps wants $width x $height\n"; 627 628 # 629 # The target model has an LCD that is suitable for this 630 # WPS 631 # 632 #print "Size requirement is fine!\n"; 633 mkdirs() if (-e "$wpsdir/$theme"); 634 # Do the copying before building the .cfg - buildcfg() 635 # mangles some filenames 636 if (defined($backdrop) && $backdrop ne "-") { 637 copybackdrop(); 638 $backdrop = "$rbdir/" . normalize($backdrop); 639 } 640 foreach my $i ($iconset, $viewericon, $remoteiconset, $remoteviewericon) { 641 if (defined($i) && $i ne "-") { 642 copythemeicon($i); 643 $i = "$rbdir/$i"; 644 } 645 } 646 foreach my $i ($font, $remotefont) { 647 if (defined($i) && $i ne "-") { 648 copythemefont($i); 649 $i = "$rbdir/fonts/$i"; 650 } 651 } 652 buildcfg(); 653 copywps(); 654 } 655 else{ 656 #print "Unknown line: $l!\n"; 657 } 658} 659 660close(WPS);