From 4bef5cf94c43dda3897489930a966919d61c1b3a Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Thu, 16 Apr 2026 22:22:25 +0200 Subject: [PATCH] small adjustments, many enhancements to rktplayer --- gui.rkt | 218 +++++++++++++++++++++++++++++++++++++++++---- gui/rktplayer.html | 8 +- gui/styles.css | 54 ++++++++++- player.rkt | 96 ++++++++++++++++---- playlist.rkt | 137 ++++++++++++++++++++++++++-- rktplayer.rkt | 2 +- translate.rkt | 2 + utils.rkt | 24 +++-- 8 files changed, 492 insertions(+), 49 deletions(-) diff --git a/gui.rkt b/gui.rkt index dd4d0ca..38ef85a 100644 --- a/gui.rkt +++ b/gui.rkt @@ -4,6 +4,8 @@ racket/runtime-path racket/gui racket-sprintf + open-app + xml "utils.rkt" "music-library.rkt" "translate.rkt" @@ -24,27 +26,37 @@ (wv-menu 'main-menu (wv-menu-item 'm-file (tr "File") #:submenu - (wv-menu (wv-menu-item 'm-select-library-dir (tr "Select Music Library Folder")) - (wv-menu-item 'm-set-lang (tr "Set language")) - (wv-menu-item 'm-quit (tr "Quit") #:separator #t))) + (wv-menu + (wv-menu-item 'm-add-tab (tr "Add Playlist")) + (wv-menu-item 'm-select-library-dir (tr "Select Music Library Folder")) + (wv-menu-item 'm-set-lang (tr "Set language")) + (wv-menu-item 'm-quit (tr "Quit") #:separator #t))) ) )) (define rktplayer% (class wv-window% (inherit-field settings icon) + (super-new [html-path "rktplayer.html"] [title "Racket Music Player"] [icon (build-path rkt-gui-dir "rktplayer.png")] ) + (define initialized (make-semaphore 0)) + (define closed #f) (define el-seeker #f) (define el-library #f) (define el-playlist #f) (define el-at #f) (define el-length #f) + (define el-rate #f) + (define el-channels #f) + (define el-bits #f) + + (define current-tab 0) (define music-library (let ((path (format "~a" (send settings get 'music-library (find-system-path 'home-dir))))) @@ -123,7 +135,7 @@ (dbg-rktplayer "Setting album art") (let ((el (send this element 'album-art))) (let ((html (format "" - (string-replace (format "~a" stored-file) "\\" "/") + (format "~a" stored-file) (current-milliseconds)))) (dbg-rktplayer "Html = ~a" html) (send el set-innerHTML! html) @@ -148,32 +160,163 @@ ) (define (update-state st) + (dbg-rktplayer "state: ~a" st) (unless (eq? st state) (dbg-rktplayer "Changing to state ~a" st) (unless (eq? state #f) ; Prevent setting src twice very fast (if (eq? st 'playing) - (set-play-button "buttons/stop.svg") + (set-play-button "buttons/pause.svg") (set-play-button "buttons/play.svg") ) ) (set! state st) ) ) + + (define/public (update-tabs) + (displayln (format "playlist = ~a" playlist)) + (let* ((tabs (send playlist tab-count)) + (html "") + (tab-el (send this element 'tabs)) + (idx 0) + ) + (while (< idx tabs) + (let ((tab-name (send playlist get-tab-name idx))) + (set! html (string-append + html + (xexpr->string + (list 'span (list (list 'id (format "tab~a" idx)) + '(class "tab")) + tab-name)))) + ) + (set! idx (+ idx 1))) + + (send tab-el set-innerHTML! html) + + (send this bind! "#tabs > span" 'click + (λ (el evt data) + (let* ((tab-id (send el id)) + (tab-idx (string->number (substring (format "~a" tab-id) 3))) + ) + (send this set-tab! tab-idx)))) + + (send this bind! "#tabs > span" 'contextmenu + (λ (el evt data) + (let* ((tab-id (send el id)) + (tab-idx (string->number (substring (format "~a" tab-id) 3))) + ) + (send this tab-context data tab-id tab-idx)))) + + (let ((id (string->symbol (format "tab~a" current-tab)))) + (let ((el (send this element id))) + (send el add-class! 'current)) + ) + ) + ) + + (define/public (tab-context evt tab-id tab-idx) + (let ((items (list + (wv-menu-item 'm-tab-rename (tr "Rename playlist") #:callback (λ () (send this rename-tab! tab-id tab-idx))) + (wv-menu-item 'm-tab-drop (tr "Remove playlist") #:callback (λ () (send this drop-tab! tab-id tab-idx))) + (wv-menu-item 'm-tab-add (tr "Add playlist") #:callback (λ () (send this add-tab))) + ) + ) + ) + + (let* ((mnu (wv-menu 'tab-popup items)) + (clientX (hash-ref evt 'clientX 60)) + (clientY (hash-ref evt 'clientY 60)) + ) + (send this popup-menu! mnu clientX clientY) + ) + ) + ) + + (define/public (drop-tab! tab-id tab-idx) + (when (= current-tab tab-idx) + (send this stop)) + (send playlist drop-tab! tab-idx) + (send this set-tab! 0) + ) + + (define/public (rename-tab! tab-id tab-idx) + (let* ((inp-id (string->symbol (format "tab-input~a" tab-idx))) + (tab-el-id (string->symbol (format "tab~a" tab-idx))) + (html (list 'input (list (list 'id (format "~a" inp-id)) + (list 'name (format "~a" inp-id)) + '(type "text") + (list 'value (send playlist get-tab-name tab-idx)) + ))) + (tab-el (send this element tab-el-id)) + (unbind-events (λ () + (send this unbind! inp-id 'change) + (send this unbind! inp-id 'blur))) + ) + (send tab-el set-innerHTML! html) + (send this unbind! tab-el-id '(click contextmenu)) + (send this bind! inp-id 'change + (λ (el evt data) + (let ((tab-name (hash-ref data 'value (send playlist get-tab-name tab-idx)))) + (send playlist set-tab-name! tab-idx tab-name) + (unbind-events) + (send this update-tabs)))) + (send this bind! inp-id 'blur + (λ (el evt data) + (unbind-events) + (send this update-tabs))) + (let ((inp-el (send this element inp-id))) + (send inp-el focus!)) + ) + ) + + (define/public (set-tab! tab-idx) + (send this stop) + (set! current-tab tab-idx) + (send playlist load-tab tab-idx) + (send this update-tabs) + (send this update-playlist) + ) + + (define/public (add-tab) + (send playlist add-tab!) + (send this update-tabs)) + + (define (update-audio-info samples rate channels bits) + (send el-bits set-innerHTML! (format "~a ~a" bits (tr "bits"))) + (send el-channels set-innerHTML! (format "~a ~a" channels (tr "channels"))) + (send el-rate set-innerHTML! (format "~a Hz" rate)) + ) + + (define (update-repeat state) + (let ((img (if (eq? state 'no-repeat) + "buttons/repeat-off.svg" + (if (eq? state 'repeat-one) + "buttons/repeat-one.svg" + "buttons/repeat.svg")))) + (let ((el (send this element 'repeat-img))) + (send el set-attr! (list 'src img))) + ) + ) (define player (new player% [time-updater update-time] [track-nr-updater update-track-nr] [state-updater update-state] + [repeat-updater update-repeat] + [audio-info-cb update-audio-info] [settings settings] )) (define inner-html-handlers (make-hash)) (define/override (page-loaded oke) + (semaphore-wait initialized) + (semaphore-post initialized) + (super page-loaded oke) - (ww-connect 'play play-or-stop) - (ww-connect 'pause pause) + (ww-connect 'play play-or-pause) + (ww-connect 'stop stop) (ww-connect 'prev previous-track) (ww-connect 'next next-track) (ww-connect 'repeat repeat) @@ -190,11 +333,19 @@ (set! el-at (send this element 'time)) (set! el-length (send this element 'totaltime)) + (set! el-rate (send this element 'rate)) + (set! el-bits (send this element 'bits)) + (set! el-channels (send this element 'channels)) + (send this set-menu! (player-menu)) (send this connect-menu! 'm-quit (λ () (send this quit))) (send this connect-menu! 'm-select-library-dir (λ () (send this select-library))) + (send this connect-menu! 'm-add-tab (λ () (send this add-tab))) + (displayln (format "page-loaded, playlist = ~a" playlist)) + (send this update-tabs) (send this update-library) + (send this update-playlist) ) @@ -284,9 +435,14 @@ (set! items (append items (list (wv-menu-item 'm-add-this (tr "Add this") #:callback (λ () (send this add-path path))))))) + (when (file-exists? (build-path path "booklet.pdf")) + (set! items (append items + (list + (wv-menu-item 'm-booklet (tr "Open booklet") #:callback (λ () (send this open-booklet path))) ;; todo check if pdf file exists + )))) + (set! items (append items (list - (wv-menu-item 'm-booklet (tr "Open booklet") #:callback (λ () (send this open-booklet path))) ;; todo check if pdf file exists (wv-menu-item 'm-folder (tr "Open containing folder") #:callback (λ () (send this open-folder path))) ))) (let* ((mnu (wv-menu 'library-popup items)) @@ -300,7 +456,7 @@ (define/public (play-path path) (dbg-rktplayer "Playing ~a" path) - (let ((pl (new playlist% [start-map path]))) + (let ((pl (new playlist% [start-map path] [settings (send settings clone 'playlists)] [id current-tab]))) (set! current-track-nr #f) (send pl read-tracks) (set! playlist pl) @@ -316,21 +472,32 @@ ) (define/public (open-booklet path) - (dbg-rktplayer "Open booklet ~a" path)) + (let ((booklet (build-path path "booklet.pdf"))) + (dbg-rktplayer "Open booklet ~a" path) + (open-app booklet))) (define/public (open-folder path) (dbg-rktplayer "path: ~a" path) - (let ((folder (if (file-exists? path) (path-only path) path))) - (open-file-manager folder))) + (open-file-manager path)) + ;(let ((folder (if (file-exists? path) (path-only path) path))) + ; (open-file-manager folder))) - (define/public (play-or-stop) - (if (eq? state 'playing) - (begin - (send player stop) - (update-time 0.0 0.0)) - (send player play-track current-track-nr)) + (define/public (play-or-pause) + (cond + ((eq? state 'playing) + (send player pause!)) + ((eq? state 'pauzed) + (send player play!)) + (else + (play-track 0)) + ) ) + (define/public (stop) + (dbg-rktplayer "Stop") + (send player stop) + (update-track-nr #f)) + (define/public (play-track idx) (send player play-track idx)) @@ -346,7 +513,14 @@ ) (define/public (repeat) - (dbg-rktplayer "Repeat") + (let ((r (send player get-repeat))) + (let ((nr (cond + ((eq? r 'no-repeat) 'repeat-all) + ((eq? r 'repeat-all) 'repeat-one) + (else 'no-repeat)))) + (send player repeat! nr) + ) + ) ) (define/public (volume) @@ -355,6 +529,7 @@ (define/public (seek-to percentage) (dbg-rktplayer "Seeking to percentage: ~a" percentage) + (send player seek percentage) ) (define/public (quit) @@ -381,9 +556,14 @@ ) (begin + (displayln "Initalizing gui") (dbg-rktplayer "ICON: ~a" (get-field icon this)) (let ((lang (send settings get 'lang 'en))) (dbg-rktplayer "RktPlayer started, current language: ~a" lang)) + (set! playlist (new playlist% [settings (send settings clone 'playlists)])) + (send player set-list! playlist) + (displayln (format "playlist = ~a" playlist)) + (semaphore-post initialized) ) ) ) diff --git a/gui/rktplayer.html b/gui/rktplayer.html index ab6b9f1..1a93048 100644 --- a/gui/rktplayer.html +++ b/gui/rktplayer.html @@ -11,8 +11,8 @@
- +
00:00:00
@@ -34,11 +34,17 @@
+
+ Default +
+
+ +
diff --git a/gui/styles.css b/gui/styles.css index 11be3d8..0200bc4 100644 --- a/gui/styles.css +++ b/gui/styles.css @@ -6,7 +6,7 @@ body { } .pane { - height: calc(100vh - 40px - 2em - 10px); + height: calc(100vh - 2em - 20px); width: calc(100% - 10px); display: flex; flex-direction: column; @@ -31,6 +31,7 @@ button { button:hover { background: #909090; + transition: all 0.5s ease-in; } @@ -69,7 +70,7 @@ input.h-slider { } .hpane { - height: 100%; + height: calc(100% - 40px - 2.5em); width: 100%; display: flex; } @@ -99,12 +100,45 @@ input.h-slider { height: 100%; } +.tabs { + width: 100%; + height: 1.5em; + border-bottom: 1px solid #505050; +} + +.tabs span.tab { + width: 50px; + overflow: hide; + text-overflow: hide; + white-space: nowrap; + border: 1px solid #505050; + cursor: default; + padding-left: 5px; + padding-right: 5px; + border-bottom: none; +} + +.tabs span.tab.current { + font-weight: bold; + color: #f3961e; +} + +.tabs span.tab:hover { + background: #e0e0e0; + color: black; + transition: all 0.5s ease-in; +} + .content { width: 100%; height: 100%; overflow: hidden; } +.music-playing .content { + height: calc(100% - 1.5em); +} + .scrolly { overflow-y: auto; } @@ -127,6 +161,7 @@ table.music-library tr td { table.music-library tr td:hover { background: #e0e0e0; color: black; + transition: all 0.5s ease-in; } .popup-menu, .popup-submenu { @@ -195,6 +230,7 @@ table.tracks tr, table.tracks td { table.tracks tr:hover { background: #e0e0e0; color: black; + transition: all 0.5s ease-in; } table.tracks tr:hover.current { @@ -218,4 +254,18 @@ table.tracks tr.current { justify-content: center; } +div.status { + width: 100%; + height: 2em; + padding-top: 0.25em; + border-left: 1px solid #505050; +} + +div.status span.info { + padding-left: 5px; + padding-right: 5px; + border-right: 1px solid #505050; + color: #d0d0d0; +} + diff --git a/player.rkt b/player.rkt index a3673bd..4f38a38 100644 --- a/player.rkt +++ b/player.rkt @@ -15,6 +15,8 @@ [time-updater (λ (time-s length-s) #t)] [track-nr-updater (λ (nr) #t)] [state-updater (λ (state) #t)] + [repeat-updater (λ (state) #t)] + [audio-info-cb (λ (current-sample rate channels bits) #t)] [buffer-max-seconds 10] [buffer-min-seconds 4] ) @@ -27,9 +29,13 @@ (define ct-data #f) (define closing #f) (define pause #f) + (define repeat-state 'no-repeat) (define ao-handle #f) (define flac-handle #f) + + (define current-music-id -1) + (define current-track-id -1) (define current-rate 0) (define current-bits 0) @@ -53,10 +59,9 @@ current-rate current-bits current-channels ao-handle) (dbg-rktplayer "Opening ao-handle") (when use-ao - (let ((fmt (ao-mk-format current-bits current-rate current-channels 'big-endian))) - (set! ao-handle (ao-open-live #f fmt)) - (start-play-time-updater) - )) + (set! ao-handle (ao-open-live current-bits current-rate current-channels 'big-endian)) + (start-play-time-updater) + ) ) ) ) @@ -74,10 +79,15 @@ 'done) (let ((seconds (ao-at-second ao-handle)) (duration (ao-music-duration ao-handle)) + (music-id (ao-at-music-id ao-handle)) ) (set! current-seconds seconds) (time-updater current-seconds duration) - (sleep 0.1) + (unless (= music-id current-music-id) + (dbg-rktplayer "a ~a ~a ~a" music-id current-track-id seconds) + (set! current-music-id music-id) + (track-nr-updater track)) + (sleep 0.2) (updater)))) (updater) ) @@ -85,6 +95,12 @@ ) ) + + (define (stream-equal? rate bits channels) + (and (= current-rate rate) + (= current-bits bits) + (= current-channels channels))) + (define (flac-play frame buffer buf-len) (unless (eq? state 'quitted) (let* ((sample (hash-ref frame 'number)) @@ -96,10 +112,27 @@ (bytes-per-sample-all-channels (* channels bytes-per-sample)) (duration (hash-ref frame 'duration)) ) + + (unless (stream-equal? rate bits-per-sample channels) + (dbg-rktplayer "Stream has changed to ~a ~a ~a" rate bits-per-sample channels) + (unless (eq? ao-handle #f) + (dbg-rktplayer "Waiting for play buffer to reach empty state") + (while (> (ao-bufsize-async ao-handle) 0) + (sleep 0.25) + ) + (dbg-rktplayer "Closing ao-handle") + (ao-close ao-handle) + (set! ao-handle #f)) + ) + (set! current-rate rate) (set! current-bits bits-per-sample) (set! current-channels channels) (set! current-length duration) + + (when (eq? ao-handle #f) + (audio-info-cb sample current-rate current-channels current-bits) + ) (check-ao-handle) (when (not (eq? ao-handle #f)) @@ -115,19 +148,21 @@ (sleep 0.25)))) (when (not (eq? ao-handle #f)) - (ao-play ao-handle second duration buffer buf-len 'flac) + (ao-play ao-handle current-track-id second duration buffer buf-len 'flac) ) ) (when pause - (dbg-rktplayer "Pauzing now...") + (dbg-rktplayer "Pausing now...") + (set-state! 'pauzed) (ao-pause ao-handle #t) (while (and (not (eq? ao-handle #f)) (not closing) pause) - (sleep 0.25)) + (sleep 0.5)) (ao-pause ao-handle #f) (dbg-rktplayer "Playing on...") + (set-state! 'playing) ) ) ) @@ -144,6 +179,7 @@ (let ((file (send ct-data get-file))) (dbg-rktplayer "opening flac handle for file: ~a" file) (set! flac-handle (flac-open file flac-meta flac-play)) + (set! current-track-id (send ct-data get-id)) (dbg-rktplayer "Starting flac-read") (let ((result (flac-read flac-handle))) (if (eq? result 'end-of-stream) @@ -202,7 +238,13 @@ ) (define/public (next-track) - (set! track (+ track 1)) + (unless (eq? repeat-state 'repeat-one) + (set! track (+ track 1))) + + (when (eq? repeat-state 'repeat-all) + (when (>= track (send pl length)) + (set! track 0))) + (if (>= track (send pl length)) (begin (set-state! 'stopped) @@ -210,7 +252,7 @@ (begin (set! ct-data (send pl track track)) (set-state! 'play) - (track-nr-updater track) + ;(track-nr-updater track) ) ) ) @@ -256,6 +298,24 @@ (set! pause (not pause)) (dbg-rktplayer "pauzed: ~a" pause) ) + + (define/public (pause!) + (set! pause #t)) + + (define/public (play!) + (set! pause #f)) + + (define/public (get-repeat) + repeat-state) + + (define/public (repeat! state) ; no-repeat, repeat-all, repeat-one + (set! repeat-state state) + (repeat-updater state) + ) + + (define/public (seek percentage) + (ao-clear-async ao-handle) + (flac-seek flac-handle percentage)) (define (state-machine) (let ((st (orig-current-seconds)) @@ -268,15 +328,17 @@ (begin (cond ((eq? state 'stopped) - (sleep 0.01)) + (sleep 0.1)) ((eq? state 'play) (if (eq? pl #f) (set-state! 'stoppped) (play-track-worker))) ((eq? state 'playing) - (sleep 0.01)) + (sleep 0.1)) ((eq? state 'track-feeded) (send this next-track)) + (else + (sleep 0.1)) ) ;(let ((ns (orig-current-seconds))) ; (when (> (- ns 5) s) @@ -286,12 +348,14 @@ ) )) (worker))) + + (define/public (set-list! playlist) + (stop-and-clear) + (set! pl playlist) + ) (define/public (play playlist) - (stop-and-clear) - ;(unless (eq? pl #f) (send pl display-tracks)) - (set! pl playlist) - ;(unless (eq? pl #f) (send pl display-tracks)) + (send this set-list! playlist) (send this play-track 0) ) diff --git a/playlist.rkt b/playlist.rkt index 7a70c44..0b22bf0 100644 --- a/playlist.rkt +++ b/playlist.rkt @@ -5,6 +5,7 @@ racket-sound "utils.rkt" racket-sprintf + "keystore.rkt" ) (provide track% @@ -12,6 +13,10 @@ ) (define the-displayln displayln) +(define list-for-each for-each) +(define list-length length) + +(define next-track-id 0) (define track% (class object% @@ -31,12 +36,19 @@ album length))) + (define my-id (begin + (set! next-track-id (+ next-track-id 1)) + (when (> next-track-id 10000000) + (set! next-track-id 1)) + next-track-id)) + (define/public (get-file) file) (define/public (get-title) title) (define/public (get-artist) artist) (define/public (get-album) album) (define/public (get-number) number) (define/public (get-length) length) + (define/public (get-id) my-id) (define (read-tags) (let* ((f (if (path? file) (path->string file) file)) @@ -148,8 +160,12 @@ (init-field [start-map #f] [max-tracks 100] + [name "Default"] + [id #f] + [settings #f] ) - + + (define store (new keystore% [filename "rktplayer.store"])) (define tracks '()) (define (can-add? file) @@ -183,16 +199,125 @@ ) ) + ;(define/public (set-name! n) + ; (set! name n)) + + ;(define/public (set-id! id*) + ; (set! id id*)) + + ;(define/public (get-id) + ; id) + + ;(define/public (get-name) + ; name) + + (define/public (tabs) + (map (λ (k) + (if (string? k) + (string->symbol k) + k)) + (send store get 'tabs '(tabkey-default))) + ) + + (define/public (tab-count) + (list-length (tabs))) + + (define/public (make-tab-key) + (string->symbol + (format "tabkey-~a-~a" (current-milliseconds) (random 10000)))) + + (define/public (get-tab-name idx) + (let* ((t (tabs)) + (entry (list-ref t idx))) + (let ((v (send store get entry (list (format "Playlist-~a" idx) '())))) + (car v)))) + + (define/public (set-tab-name! idx name) + (let* ((t (tabs)) + (entry (list-ref t idx)) + (v (send store get entry (list (format "Playlist-~a" idx) '()))) + ) + (send store set! entry (list name (cadr v))) + ) + ) + + (define/public (tab-id idx) + (let ((t (tabs))) + (list-ref t idx))) + + (define/public (tab-index id) + (let ((t (tabs))) + (letrec ((f (λ (t idx) + (if (null? t) + #f + (if (eq? (car t) id) + idx + (f (cdr t) (+ idx 1))))))) + (f t 0)))) + + (define/public (drop-tab! idx) + (let* ((t (tabs)) + (entry (list-ref t idx)) + ) + (send store set! 'tabs (list-drop! t idx)) + (send store drop! entry) + )) + + (define/public (add-tab!) + (let* ((t (tabs)) + (new-entry (send this make-tab-key))) + (send store set! 'tabs (append t (list new-entry))) + ) + ) + + (define/public (save-tab!) + (let* ((entry id) + (idx (send this tab-index entry)) + ) + (displayln (format "entry id = ~a, ~a" entry idx)) + (if (eq? idx #f) + (err-rktplayer "Cannot get tab for id ~a" entry) + (let ((value (list (send this get-tab-name idx) + (map (λ (track) + (format "~a" (send track get-file))) + tracks)))) + (send store set! entry value) + ) + ) + ) + ) + + (define/public (load-tab idx) + (let* ((t (tabs)) + (entry (list-ref t idx)) + ) + (displayln (format "loading ~a" entry)) + (set! id entry) + (set! tracks '()) + (let ((value (send store get entry (list "Default" '())))) + (set! name (car value)) + (list-for-each (λ (file) + (send this add-track file #f)) + (cadr value)) + ) + ) + #t + ) + (define/public (read-tracks) (set! tracks '()) (read-tracks-internal start-map) + (send this save-tab!) ) (define/public (length) (list-len tracks)) - (define/public (add-track file) - (add-track* file)) + (define/public (add-track file . args) + (add-track* file) + (when (null? args) + (send this save-tab!)) + ) (define/public (track i) (list-ref tracks i)) @@ -244,9 +369,11 @@ (mktable rows 'tracks formatter)))) (super-new) + (begin - (when (eq? start-map #f) - (error "Initialize playlist% with a starting map")) + (if (eq? start-map #f) + (send this load-tab 0) + (set! id (send this tab-id id))) ) ) ) diff --git a/rktplayer.rkt b/rktplayer.rkt index a195ca2..3f02c3d 100644 --- a/rktplayer.rkt +++ b/rktplayer.rkt @@ -44,7 +44,7 @@ )) (window (new rktplayer% [wv-context context])) ) - (send window devtools) + ;(send window devtools) window) ) diff --git a/translate.rkt b/translate.rkt index e91b018..cd519a2 100644 --- a/translate.rkt +++ b/translate.rkt @@ -51,3 +51,5 @@ ('nl "Kies de map met de Muziek Bibliotheek")) (add "Quit" ('nl "Beëindigen")) +(add "channels" + ('nl "kanalen")) diff --git a/utils.rkt b/utils.rkt index 955f25c..3adc533 100644 --- a/utils.rkt +++ b/utils.rkt @@ -19,6 +19,7 @@ warn-rktplayer fatal-rktplayer (all-from-out simple-log) + list-drop! ) @@ -50,6 +51,13 @@ ) ) +(define (list-drop! l idx) + (if (null? l) + l + (if (= idx 0) + (cdr l) + (cons (car l) (list-drop! (cdr l) (- idx 1)))))) + (define (make-delayed-reactor seconds closure) (let* ((last-val #f) (last-time -1) @@ -87,11 +95,17 @@ ) (define (open-file-manager path) - (let ((folder (if (path? path) (path->string path) path))) - (case (system-type 'os) - [(windows) (process (string-append "explorer.exe " folder))] - [(macosx) (process (string-append "open " folder))] - [else (process (string-append "xdg-open " folder))])) + (let ((folder (if (path? path) (path->string path) path)) + (do-open (λ (prg arg) + (let ((exe (find-executable-path prg))) + (dbg-rktplayer "(process* ~a ~a)" exe arg) + (process* exe arg)))) + ) + (dbg-rktplayer "open-file-manager ~a" folder) + (case (system-type 'os) + [(windows) (do-open "explorer.exe" folder)] + [(macosx) (do-open "open" folder)] + [else (do-open "xdg-open" folder)])) ) (define (basedir file)