Projects | dPlayer


Home | HowTo | The Code | Say Thanks



dPlayer is written in PHP, JS and CSS with some additional resources


You may download all these files in a single archive:
Download dPlayer.zip



The Server-Side: PHP

Here we handle basic GUI display, including parsing the specified folder to find or build a playlist.
dPlayer PHP SOURCE CODE:
>Show More<
<?php
    
##  *    ~~ dPlayer.php  V 4.0  ~~
##  *  Copyright Kirk Siqveland 2022
##  *       Edmonds, WA - USA

##  * Core of - dPlayer -
##  * HTML5 Dynamic-Audio Player with Auto-Playlist
    
##  * dPlayer identifies the playable files, builds a playlist and lets you play all the
##  * files in that folder/directory.  If you organize music from albums into folders this
##  * lets you manage the "Playlist" by just adding/removing/renaming items from the folder.
##
##  * Other Features 
##      - can work with no parameters from the folder to be played.
##      - work from the player directory by passing the path to the directory to play.
##      - Auto-builds playlists based on alpha-sort of files.
##          -- With specific naming practices titles are pared to only the song-name
##          -- Simple rename file with a starting number e.g. 05_-_Peter_Gabriel_-_In_Your_Eyes.flac
##      - Use dPlayer playlist file format (.tags) for album and song information and play order.
##      - Use .m3u and .m3u8 playlists for audio file play order.
##      - TO-DO extract more info from the playlists...
##

session_start();
    
    ## Set up Basic Variable for the embeded player page:
        $foundPlaylist  = ""              ;   ##  Flag - use of playlist in the host folder.
        $PlayerPath     = ""                 ;   ##  Path to the dPlayer components directory.


    ## Get the current URL and directory paths
        getPaths()                           ;
        findMyHome($PlayerPath)              ;   

    ## Let's Go:
        $playList  = BuildPlayList()         ;
        $mp3List   = BuildPlayList(true)     ;
        $pegTally  = 0                       ;

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="author" content="Kirk Siqveland" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
    <title>HTML5 Dynamic Audio player with auto-playlist</title>

    <!-- add styles and scripts -- $PlayerPath allows a single folder to have all the other files we need -->
    <link   type="text/css"        href="<?php echo $PlayerPath;?>dPlayer.css" rel="stylesheet" />
    <script type="text/javascript" src ="<?php echo $PlayerPath;?>dPlayer.js"></script>
    <script type="text/javascript" src ="<?php echo $PlayerPath;?>KBSliderX.js"></script>    

</head>
<body>
    <div class="centerbox">
        <div class="debugger hidden"><?php echo $DebugMsg; ?></div>
        <div class="nojsmsg"><br/>
            <h2>The dPlayer Audio Player requires JavaScript, which seems to be unavailable!</h2><br/>
        </div>
        <div class="player hidden">
            <div class="pl"  title="Play List"></div>
            <div class="title"></div>
            <div class="subtitle"></div>
            <div class="album"></div>
            <div class="cover">
                <img id="splash">
            </div>
            <div class="controls">
                <div class="play"  title="Play"></div>
                <div class="pause" title="Pause"></div>
                <div class="prev"  title="Previous"></div>
                <div class="rew"   title="Restart"></div>
                <div class="fwd"   title="Next"></div>
            </div>
            <div class="toggles">          
                <div class="mp3on"  title="MP3 - On"></div> 
                <div class="mp3off" title="MP3 - Off"></div>
                <div class="wavon"  title="MP3 - Off"></div>  
                <div class="wavoff" title="MP3 - On"></div>
            </div>
            <div class="KBSlider" id="volume"  title="Volume"></div>
            <div class="KBSlider" id="songbar" title="Progress"></div>
        </div>

        <ul class="wavlist hidden">
            <?php echo $playList; ?>
        </ul>
        <ul class="mp3list hidden">
            <?php echo $mp3List; ?>
        </ul>        
    </div>

    <!-- This is used to communicate with page hosting this page as an iFrame -->
        <script  src="<?php echo $PlayerPath;?>iframe_guest.js"></script>
</body>
</html>

<?php    

## ==============================================================================
##                  S u b - R o u t i n e s
## ==============================================================================

function BuildPlayList($asMP3List = false){
    global $CoverArt, $playPath, $FlagVarious, $DebugMsg, $pegTally,  $Performer, $AlbumName ;
    //$localPath = server path to this file (may be source may be play)
    //$playPath   = relative path to the directory with audio files
    $pegTally   = 0                             ;
    $playPath   = $_GET["audiopath"]            ;
    $localRoot  = $_SERVER['DOCUMENT_ROOT']     ;
        // $serverName  = $_SERVER['SERVER_NAME']            ;
        // $CurDirPath  = dirname($_SERVER['PHP_SELF'])      ;
    
    if (empty($playPath)){
        $playPath   = "."  ;
        $localPath  = str_replace($_SERVER['DOCUMENT_ROOT'], "" , __DIR__).'/' ; // Local Path
        $playPath   = CurDirPath.'/'     ; // - as URL
    }else{ 
        
            if(substr($playPath,0,1)!=="/"){ $playPath = '/' . $playPath        ; }
            if(substr($playPath,-1)!=="/"){ $playPath .= '/'                    ; }
        // Strip $playPath back to a local relative path
        $localPath  = str_replace($_SERVER['DOCUMENT_ROOT'], "" , $playPath)    ;   
        $playPath   = rootURL.$localPath		                                ;
    }       

    ## - Scan the current directory for audio files.
    ## Open the current directory | Read Line-BY-Line into $dirArray | Close directory
        if($asMP3List){ 
            $tryPath = $localRoot.$localPath."mp3/" ;
        }else{
            $tryPath = $localRoot.$localPath        ;
        }

        if (is_dir($tryPath)){
            if ($dh = opendir($tryPath)){
                // $DebugMsg .= "Success opening dir: $tryPath  <br>" ;
                if($asMP3List){ $playPath   .= "mp3/" ; }
                while (($file = readdir($dh)) !== false){
                    if(is_file($tryPath.$file)){
                        // $DebugMsg .= "Test-Stub -- filename: -" . $file . "- <br>" ;
                        $dirArray[]=$file ;
                    }
                    clearstatcache() ;
                }
                closedir($dh);
            }
        }    

    ## Count elements in array
        $indexCount = Count($dirArray) ;
        // $DebugMsg .= "indexCount - file in dir: $indexCount  <br>" ;        
    ## EXIT on EMPTY
        if($indexCount == 0){ 
            $DebugMsg .= "No files in dirArray [Trypath] : $tryPath<br/>" ;
            return "";
        }else{ $DebugMsg .= "$indexCount Files found in dirArray [Trypath] : $tryPath<br/>";}

    ## Now loop through the array of files to find our Artist/Album/Art-tags file
    ## This assumes Named like:
    ##       Artist_-_AlbumName_-_CoverArtFileName.tags
    ## e.g.  Pink_Floyd_-_Dark_Side_of_the_Moon_-_AlbumArt.jpg.tags
    ## This file can be empty, we only use the name.
        // $DebugMsg .= "indexCount = $indexCount <br/>" ;
        for($tick=0; $tick < $indexCount; $tick++) 
        {
            $fileName  =  $dirArray[$tick] ;

            ##  Stub I'm not using but left in in case someone needs it...
            //  $testname = strtolower($fileName) ;
            //  if($testname == "albumart.jpg"||$testname == "albumart.png"||$testname == "coverart.jpg"||$testname == "coverart.png"){ 
            //      $albumArt = $fileName ; 
            // }

            // $DebugMsg .= "Tick dirArray $tick - file: $fileName <br/>"  ;
            $extn=pathinfo($fileName, PATHINFO_EXTENSION) ;

            if($extn == "m3u"||$extn == "m3u8"){
            ## - TODO - Extract more information from m3u files
                ## Assumes music in folders organized by - Performer/Album-or-Performance/All-Songs-and-Audio -
                        $Performer = dirname(__DIR__, 2)    ;
                        $AlbumName = dirname(__DIR__, 1)    ;
                        $foundPlaylist = $dirArray[$tick]   ;
                        $DebugMsg .= "Found Playlist - $fileName <br/>"  ;
            }

            if($extn == "tags"){            
                    $NamePart   = explode ( "_-_" , $fileName )              ;
                        $Performer  = tidyName( $NamePart[0] )               ;
                        $AlbumName  = tidyName( $NamePart[1] )               ;
                            $Cover  = str_replace(".tags","", $NamePart[2])  ;
                        $AlbumArt   = $localPath.$Cover                      ;
                        $CoverArt   = $localPath.$Cover                      ;
                        $foundPlaylist = $dirArray[$tick]                    ;
                        $DebugMsg .= "Found Playlist - $fileName <br/>"      ;
            }
        } /*/ indexCount Loop /*/

$DebugMsg .= "Tags/mp3 File: $foundPlaylist <br/>"  ;

        if(!empty($foundPlaylist)){

                $lPerformer = strtolower($Performer) ;
                    if (strpos($lPerformer,"various")>0 || $lPerformer == "mixtape" || $lPerformer == "mix tape" || $lPerformer == "mix-tape" || $lPerformer == "mix_tape")
                    {   $Performer = ""                     ;
                        $FlagVarious   = true               ;
                    }else { 
                        $FlagVarious   = false              ;
                    }                 

                        $playListPath = $tryPath.$foundPlaylist  ;
                    $fn = fopen($playListPath,"r")          ;
                    if($fn == false){
                        $DebugMsg .= "fOpen Playlist failed! $playListPath<br/>" ;
                    }else{

                        $firstLine = fgets($fn)         ;

                        ## The first line should start with Playlist: 
                        if(strpos($firstLine, 'Playlist:') !== false )
                        {
                            // $foundPlaylist = true           ;
                            // $foundPlaylist = $foundPlaylist;

                            while(! feof($fn))  {
                                ## Get next line in the file

                                    $fullLine  = explode('|',fgets($fn)) ;
                                    $firstPart = trim($fullLine[0]) ;

                                ## Respond according to line type
                                if(!empty($firstPart))
                                {
                                    if(substr($firstPart, 0, 1)=='#')
                                    {
                                            if(substr($firstPart, 1, 1)=='@')
                                            {
                                                $metaInfo = explode('=',$firstPart);
                                                $mTag = strtolower(trim($metaInfo[0]))   ;
                                                switch($mTag)
                                                {
                                                    case "@performer":
                                                        $XPerformer = trim($metaInfo[1]) ;
                                                        break;

                                                    case "@composer":
                                                        $XComposer = trim($metaInfo[1])  ;
                                                        break;

                                                    case "@album":
                                                        $XAlbum = trim($metaInfo[1])     ;
                                                        break;     

                                                    case "@subtitle":
                                                        $XSubtitle = trim($metaInfo[1])  ;
                                                        break;

                                                    case "@albumart":
                                                        $XAlbumArt = trim($metaInfo[1])  ;
                                                        break;

                                                    case "@date":
                                                        $XDate = trim($metaInfo[1])      ;
                                                        break;
                                                }
                                            }
                                    }elseif (substr($firstPart, 0, 1)=='|') 
                                    {   // Ignore insert-line lines      
                                    }elseif (substr($firstPart, 0, 1)=='$') 
                                    {   // Ignore insert-heading lines
                                    }elseif (substr($firstPart, 0, 1)=='!') 
                                    {   // $titleTally += 1                  ;
                                        // $PlayTitles[substr($firstPart, 1)] ;                                   
                                    }else
                                    {   @$extn=pathinfo($firstPart, PATHINFO_EXTENSION) ;   // Get file extension
                                        if ($extn == "flac"||$extn == "mp3"||$extn == "ogg"||$extn == "oga"||$extn == "wav")
                                        {
                                            $fHandle   = fopen($playPath.$firstPart,"r") ;
                                                if($fHandle  !== false)
                                                {              
                                                    if(count($fullLine)>1){ 
                                                        $CoverArt = $localPath.trim($fullLine[1]) ; 
                                                        // $DebugMsg .= " Extra CoverArt: $firstPart == $CoverArt"  ;
                                                    }else{
                                                        $CoverArt = $AlbumArt ;
                                                    }

                                                    $playList .= li_Details($firstPart, $asMP3List)  ; 
                                                    $pegTally++                                     ;
                                                    // $DebugMsg .= " Added from PlayList: $firstPart"  ;
                                                    // $DebugMsg .= " -:- Performer = $Performer  :: " ; 
                                                    // $DebugMsg .= " AlbumName = $AlbumName<br/>"     ;                                                     
                                                }else{
                                                    $DebugMsg .= "Unable to find $playPath$firstPart<br/>"  ;
                                                }
                                            fclose($fHandle) ;                                                    
                                        }  
                                    }                                      
                                } #/ if(!empty($firstPart))
                            } #/    while(! feof($fn))
                        }else{ 
                            $DebugMsg .= "Empty Playlist <br/>" ;
                            $foundPlaylist = "" ;
                        } #/    if(strpos($firstLine, 'Playlist:') !== false )

                        fclose($fn);
                    }
        } #/ endif !foundplaylist

        if(empty($foundPlaylist)||empty($playList)){
            
            ## Sort file list array
                sort($dirArray) ; 

            ## Loop through the array of files to build a playlist
                for($tick=0; $tick < Count($dirArray) ; $tick++) 
                {                        
                    $playName= $dirArray[$tick] ;  // Gets File Names
                    ## Find Audio files by ending, and add them to the list
                        $extn = pathinfo($playName, PATHINFO_EXTENSION) ; // Get file extension
                        $extn = strtolower($extn) ;

                        if ($extn == "flac"||$extn == "mp3"||$extn == "ogg"||$extn == "oga"||$extn == "wav"){
                            $playList .= li_Details($playName, $asMP3List)  ;
                            $pegTally++                                     ;
                            // $DebugMsg .= "Added $playName"  ;
                            // $DebugMsg .= " - From folder Performer = $Performer  :: "      ; 
                            // $DebugMsg .= " AlbumName = $AlbumName<br/>"      ;  
                        }
                }#/ end For Loop
        }        

        if(empty($playList))
        {       return ""           ;
        }else{  return $playList    ;
        }        
}



## - List Item Information Extraction Routines -
## This assumes audio files are named using "_-_" as a delimiter between tags
## For dPlayer to work audio-file names must be in this order:

## Notice the Track # is used to help sort files of an album by name and retain
## propper play order.

## (if used)  - Artist name
## (if used)  - Track # -or- Artist name -or- Album name if MixTape or Artist first
## (required) - Track # -or- Artist name if MixTape
## (required) - Song Title
## e.g.   Pink_Floyd_-_Dark_Side_of_The_Moon_-_09_-_Eclipse.flac
## or       09_-_Eclipse.flac
## For Various Artist / MixTape Albums use 03_-_Pink_Floyd_-_Eclipse.flac

    function splitMediaName($MediaName){
        global $Artist, $AlbumName, $Performer, $FlagVarious, $XPerformer, $XAlbum ;

        if (strpos($MediaName, '_-_') !== false) 
        {
            $NamePart       = explode ( "_-_" , $MediaName ) ;
            $partsCount     = count($NamePart)               ;
            $XSong          = ""                             ;
            switch($partsCount){
                case 2:
                    if (is_numeric($NamePart[0])){
                        $Song       = tidyName( $NamePart[1] , $XSong   ) ;
                    }else{
                        $Artist     = tidyName( $NamePart[0] , $XArtist ) ; 
                        $Song       = tidyName( $NamePart[1] , $XSong   ) ;
                    }   
                    break ;

                case 3:
                    if(preg_match("/^[A|B][0-9]*/", $NamePart[0]) || $FlagVarious  == true ){
                        //$AlbumName   = "MixTape" ;
                        $FlagVarious = true                                 ;
                        $Artist      = tidyName( $NamePart[1] , $XArtist )  ;
                        $Song        = tidyName( $NamePart[2] , $XSong   )  ;
                    }else{                       
                        $Artist      = tidyName( $NamePart[0] , $XArtist )  ;
                        $AlbumName   = tidyName( $NamePart[1] , $XAlbum  )  ;
                        $Song        = tidyName( $NamePart[2] , $XSong   )  ;
                    }
                    break ;

                case 4:
                        $Artist      = tidyName( $NamePart[0] , $XArtist )  ;
                        $AlbumName   = tidyName( $NamePart[1] , $XAlbum  )  ;
                        $Song        = tidyName( $NamePart[3] , $XSong   )  ;
                    break;                    

                default:
                    $Song            = tidyName( $MediaName   , $XSong   )  ;
                    break ;

            } //switch($partsCount)
        }else{
            $Song = tidyName( $MediaName , $XSong   )  ;
        }
        
        return $Song ;  // function splitMediaName()
    }   

    function tidyName($rawName, $default = ""){
        if(!empty($default)){               $rawName = $default ; }
        $outName = str_replace('%20', ' ',  $rawName)           ;
        $outName = str_replace('-_', chr(39).' ', $outName)     ;    
        $outName = str_replace('_-',' - ', $outName)     ;   
        $outName = htmlspecialchars(        $outName)           ;        
        $outName = preg_replace("/_/", " ", $outName)           ;
        return $outName ;
    }

    function li_Details($name, $fromMP3 = false){
        global $Artist, $AlbumName, $CoverArt, $Performer, $FlagVarious, $playPath, $pegTally, $DebugMsg ;
            if (empty($CoverArt)){
                $CoverArt = $playPath."CoverThumb.jpg" ;
                if(is_file($CoverArt)===false){$CoverArt = $PlayerPath."CoverThumb.jpg" ;}
            }

            $SMN      = splitMediaName($name) ;
            $SongName = str_replace(array(".flac", ".mp3", ".ogg", ".oga", ".wav"),"",$SMN) ;
            if($fromMP3){   $listClass = "mp3Item"  ; 
            }else{          $listClass = "wavItem"  ; }

            if($FlagVarious){
                return "<li class='$listClass' peg='$pegTally' audiourl='$playPath$name' title='$SongName' subtitle='$Artist' cover='$CoverArt' album='$AlbumName'>$SongName<br/>      <small> - $Artist</small></li>"; 
            }else{
                return "<li class='$listClass' peg='$pegTally' audiourl='$playPath$name' title='$SongName' subtitle='$Performer' cover='$CoverArt' album='$AlbumName' >$SongName</li>";
            }     
    }  

    function findMyHome(&$PlayerPath){
        ## Here we look first up two, then up one directory for a folder named "player" to contain all the player files        
        ## - Assuming we are in a specific media folder such as...
        ##      www.mydemodomain.org/wikiroot/media/Pink_Floyd/Metal
        ## - e.g. www.mydemodomain.org/wikiroot/media/player
        ## Barring that we see if a player.dir file was saved to the web-root "www.mydemodomain.org/"
        ## And if all else fails we look in the folder we are already in...

            $lPath = str_replace(CurDirPath, "", __DIR__)               ;
            $upTwo = dirname(__DIR__, 2)                                ;
            $upOne = dirname(__DIR__, 1)                                ;
        if(file_exists("$upTwo/dplayer/dPlayer.css")){
            $PlayerPath = "$upTwo/dplayer/"                              ;
            $PlayerPath = str_replace($lPath, "", $PlayerPath)          ;            
        }else if(file_exists("$upOne/dplayer/dPlayer.css")){
            $PlayerPath = "$upOne/dplayer/"                              ;
            $PlayerPath = str_replace($lPath, "", $PlayerPath)          ;
        }else{
            if(file_exists(rootURL."/player.dir")){
                $PlayerPath = file_get_contents(rootURL."/player.dir")  ;                
            }else{
                if(file_exists("dPlayer.css")){
                    $PlayerPath = __DIR__ . '/'                         ;
                    $PlayerPath = str_replace($lPath, "", $PlayerPath)  ;
                }else{ $PlayerPath = "Couldn't find a Path!"            ; 
                }
            }
        }
    } #/ findMyHome()

    function getPaths(){
    // I'm sure there is a cleaner way to do this but other things I have tried haven't worked.
        if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on'){     
            if (!defined('rootURL')){  define('rootURL', 'https://'.$_SERVER['HTTP_HOST']) ;   }
        }else{      
            if (!defined('rootURL')){  define('rootURL', 'http://'. $_SERVER['HTTP_HOST']) ;   }
        }
        if (!defined('CurDirPath')){   define('CurDirPath', dirname($_SERVER['PHP_SELF'])) ;   }        
    }  

?>


The Client-Side: JS

Here we handle user interface actions, playback, File Selection and transports (Play, Pause, Stop etc.)
dPlayer GUI JS SOURCE CODE:
>Show More<
/**
 *  ~~ dPlayer.php  V 4.0  ~~
 *
 *  Part of - dPlayer -
 *  HTML5 Dynamic-Audio Player with Auto-Playlist
 *
 *  Copyright Kirk Siqveland 2022
 *
 *  HTML5 Dynamic-Audio Player with Auto-Playlist
 *
 *
 *
 **/

var audio            ; // define later as HTML5 audio object...

    
                /**  D I Y  **/
function KBSliderCallBack(ID, Progress, Pixels = -1, maxPixels = -1, source = "click"){
// Add your Code to respond to slider Changes Here:
  // console.log( "KBSlider Callback: ID = " + ID + " | Progress = " + Progress ) ;
  // console.log( "Pixels = " + Pixels + " of " + maxPixels   ) ;

  switch(ID){
    case "volume":
        audio.volume = Progress/100 ;
        // console.log( "KBSlider Callback: volume = " + audio.volume ) ;
        break ;
    case "songbar":
        // console.log( "KBSlider Callback: audio.duration = " + audio.duration ) ;    
        let setTime = parseInt(audio.duration*Progress/100) ;
        audio.currentTime = setTime                         ; 
        break ;
  }

}


document.addEventListener("DOMContentLoaded", function() {
    // Show the dPlayer and hide the "No JS" Message
        var nojsmsg = document.getElementsByClassName('nojsmsg')[0]    ;
            nojsmsg.classList.add('hidden')    ;
        var dPlayer = document.getElementsByClassName('player')[0]     ;
            dPlayer.classList.remove('hidden') ;        

    var tick     ;    // General use increment
    var useMP3      = true            ;
    // var audio                        ; // moved definition to KBSlider.js
    var pegCur      = 0               ;
    var pegNext     = 1               ;
    var pegPrev     = 0               ;
    var playing     = 0               ;
    var playlisting = 0               ;
    var opacity     = 0               ;
    var intervalID  = 0               ;
    var playItems	= 'wavItem' 		;

    var wavFiles    = document.getElementsByClassName('wavItem')    ;
    var mp3Files    = document.getElementsByClassName('mp3Item')    ;
    var listitems   = document.getElementsByClassName('mp3Item')    ;

    var playbtn     = document.getElementsByClassName('play')[0]     ;
    var pausebtn    = document.getElementsByClassName('pause')[0]    ;   
    var prevbtn     = document.getElementsByClassName('prev')[0]     ;
    var rewbtn      = document.getElementsByClassName('rew')[0]      ;
    var fwdbtn      = document.getElementsByClassName('fwd')[0]      ;
    var showpl      = document.getElementsByClassName('pl')[0]       ;

    var toggles     = document.getElementsByClassName('toggles')[0]  ;
    var mp3onbtn    = document.getElementsByClassName('mp3on')[0]    ;
    var wavonbtn    = document.getElementsByClassName('wavon')[0]    ;
    var mp3offbtn   = document.getElementsByClassName('mp3off')[0]   ;
    var wavoffbtn   = document.getElementsByClassName('wavoff')[0]   ;

    var audiolist   = ''   ;
    // var bugWatch = document.getElementsByClassName("debugger")[0] ;
    //     e.g. bugWath.innerHTML += "Some debug message...</br>"    ;


    if( useMP3 === false || listitems.length === 0){ 
            useMP3      = false             ;
            toggles.classList.add('hidden') ; 
            listitems   = document.getElementsByClassName('wavItem')    ;                
            audiolist   = document.getElementsByClassName('wavlist')[0] ;
    }else{ 
            audiolist   = document.getElementsByClassName('mp3list')[0] ; 
    }    

    if(listitems.length === 0){
        console.log("No files found!") ;
        return 0;
    }    
    
    wavonbtn.classList.add('hidden')   ;   
    mp3offbtn.classList.add('hidden')  ;

// -------------------------------------------------------------------------

    function initAudio(PLindex) {

        var peg         = parseInt(PLindex)         ;
        var liCount     = listitems.length          ;
        // console.log ("initiAudio -- Peg: "+ peg + " - of " + liCount)	;
        // console.log ("initiAudio -- useMP3: "+ useMP3) ;

            if(PLindex == 0){
                pegCur  = 0                         ;
                pegNext = 1                         ;
                pegPrev = (liCount - 1).valueOf()   ;
            }else if (peg >= liCount){
                pegCur  = 0                         ;
                pegNext = 1                         ;
                pegPrev = (liCount - 1).valueOf()   ;            
            }else if (peg < 0){
                pegCur  = (liCount - 1).valueOf()   ;
                pegNext = 0                         ;
                pegPrev = (liCount - 2).valueOf()   ;
            }else{
                pegCur  = peg                       ;
                pegNext = (peg + 1).valueOf()       ;
                pegPrev = (peg - 1).valueOf()       ;               
            }
        var url         = pegAttrib('audiourl', pegCur) ;
        var title       = pegAttrib('title', pegCur)    ;
        var subtitle    = pegAttrib('subtitle', pegCur) ;
        var album       = pegAttrib('album', pegCur)    ;
        var cover       = pegAttrib('cover', pegCur)    ;

                
        setText('title', title)                         ;
        setText('subtitle', subtitle)                   ;
        setText('album', album)                         ;
        document.getElementsByClassName("cover")[0].style.backgroundImage = "url('" + cover + "')" ;
        document.getElementById("splash").src = cover ;

        try {audio.removeEventListener("ended", rollNextAudio)      ; }
        catch(err) {console.log("Audio.eListener no 'ended' event") ; }

        // console.log("pegCur = " + pegCur + " - pegPrev = " + pegPrev + " - pegNext = " + pegNext) ;
        for (var tick = 0; tick < listitems.length; tick++) 
        {   listitems[tick].classList.remove("active")              ; }
            listitems[pegCur].classList.add('active')   ;

        audio = new Audio(url)                          ;
        audio.addEventListener('timeupdate',cbPlayTime) ;
        audio.addEventListener('loadedmetadata', function () {
            if(playing == 1){ playAudio() ; }
        });

    } //end - initAudio()myprogbox.style.opacity = "0.8" ;

    function rollNextAudio(){        
        initAudio(pegNext)                                  ;
    }    

    function cbPlayTime(){
        let curtime = audio.currentTime                         ; 
        let pbRatio = parseInt(curtime / audio.duration * 100)  ;
        SetProgress("songbar", pbRatio) ;
    }

    function playAudio() {
        audio.addEventListener('ended', rollNextAudio, false) ;
        audio.play()                                        ;
        playing = 1                                         ;
            playbtn.classList.add('hidden')                 ;
            pausebtn.classList.add('visible')               ;
    }

    function stopAudio() {
        audio.pause()                                       ;
        playing = 0                                         ;
            playbtn.classList.remove('hidden')              ;
            pausebtn.classList.remove('visible')            ;
    }

    function pauseAudio() {
        audio.pause()                                       ;
            playbtn.classList.remove('hidden')              ;
            pausebtn.classList.remove('visible')            ;
    }


      function swap2wav(){
            // Show
            wavonbtn.classList.remove('hidden')             ;
            wavonbtn.classList.add('visible')               ;  
            mp3offbtn.classList.remove('hidden')            ;
            mp3offbtn.classList.add('visible')              ;

            // Hide
            mp3onbtn.classList.remove('visible')            ;
            mp3onbtn.classList.add('hidden')                ;
            wavoffbtn.classList.remove('visible')           ;
            wavoffbtn.classList.add('hidden')               ;
            playItems  = 'wavItem'                          ;
            useMP3 = false ;
            
                if(playlisting == 1){                     
                    listitems  = document.getElementsByClassName('mp3Item') ;
                        for (var tick = 0; tick < listitems.length; tick++) 
                        {   listitems[tick].classList.remove("active")      ; }
                    listitems  = document.getElementsByClassName('wavItem') ;
                    listitems[pegCur].classList.add('active')               ;

                    audiolist.classList.remove('visible')     ;
                    audiolist.classList.add('hidden')         ; 
                    audiolist  = document.getElementsByClassName('wavlist')[0]  ;                    
                    audiolist.classList.remove('hidden')      ;
                    audiolist.classList.add('visible')        ;                     
                }             
            // window.location.reload(true)                ;
        }
        function swap2mp3(){
            // Show
            mp3onbtn.classList.remove('hidden')            ;
            mp3onbtn.classList.add('visible')              ;
            wavoffbtn.classList.remove('hidden')           ;
            wavoffbtn.classList.add('visible')             ; 

            // Hide
            wavonbtn.classList.remove('visible')           ;
            wavonbtn.classList.add('hidden')               ;  
            mp3offbtn.classList.remove('visible')          ;
            mp3offbtn.classList.add('hidden')              ;          
            playItems  = 'mp3Item'                         ;
            useMP3 = true ;

                if(playlisting == 1){       
                    listitems  = document.getElementsByClassName('wavItem')   ;
                    for (var tick = 0; tick < listitems.length; tick++) 
                    {   listitems[tick].classList.remove("active")           ; }
                    listitems  = document.getElementsByClassName('mp3Item')   ;
                    listitems[pegCur].classList.add('active')                ;

                    audiolist.classList.remove('visible')     ;
                    audiolist.classList.add('hidden')         ;
                    audiolist  = document.getElementsByClassName('mp3list')[0]  ;
                    audiolist.classList.remove('hidden')      ;
                    audiolist.classList.add('visible')        ;                      
                }              
        }    

    // show playlist
        function showPlaylist(){
            if(playlisting == 0){
                audiolist.style.opacity = 0               ;
                audiolist.classList.remove('hidden')      ;
                audiolist.classList.add('visible')        ;                
                intervalID  = setInterval(fadeInPL, 60)   ;
                playlisting = 1                           ;
            }else{      
                intervalID  = setInterval(fadeOutPL, 40)  ;
                playlisting = 0                           ;
            }            
        }     

    // Return Attributes of a specific Play List Item
       function pegAttrib(AttribName, peg = 0){
            var listpeg     = parseInt(peg) ;
            // var listitems   = document.getElementsByClassName(playItems)   ;
            if(listitems.length > 0){
                return listitems[listpeg].getAttribute(AttribName) ;
            }else{
                return "" ;
            }
            
        }

        function setText(ClassName, newText) {
            document.getElementsByClassName(ClassName)[0].innerHTML = newText ; 
        }   

        function fadeOutPL(){
          opacity = Number(window.getComputedStyle(audiolist).getPropertyValue("opacity")) ;
            if(opacity > 0){
                opacity = opacity - 0.1                 ;
                audiolist.style.opacity = opacity       ;
            }else{
                clearInterval(intervalID)               ;
                audiolist.classList.remove('visible')   ;
                audiolist.classList.add('hidden')       ;  
            }
        }  
        function fadeInPL(){
          opacity = Number(window.getComputedStyle(audiolist).getPropertyValue("opacity")) ;
            if(opacity < 1){
                opacity = opacity + 0.1                 ;
                audiolist.style.opacity = opacity       ;
            }else{
                clearInterval(intervalID)               ;
            }
        }

 /* -------------------------------------------------------------/
                Main Procedures - Setup UI events
/--------------------------------------------------------------*/
    // play click
        playbtn.addEventListener("click", function(e){
            e.preventDefault()                       ;
            playAudio()                              ;
        });

    // pause click
        pausebtn.addEventListener("click", function(e){
            e.preventDefault()                        ;
            stopAudio()                               ;            
        });

    // previous click
        prevbtn.addEventListener("click", function(e){     
            e.preventDefault()                       ;
            pauseAudio()                             ;
            initAudio(pegPrev)                       ;
            SetProgress("songbar", 0)                ;
        });

    // rewind click
        rewbtn.addEventListener("click", function(e){     
            e.preventDefault()                      ;
            pauseAudio()                            ;
            initAudio(pegCur)                       ;
            SetProgress("songbar", 0)               ;
        });

    // forward click
        fwdbtn.addEventListener("click", function(e){
            e.preventDefault()                      ;
            pauseAudio()                            ;
            initAudio(pegNext)                      ;
            SetProgress("songbar", 0)               ;
        });

  
    // add on-mp3button click
        mp3onbtn.addEventListener( "click", swap2wav, false ) ;
        wavoffbtn.addEventListener("click", swap2wav, false ) ;
    // add on-wavbtn click
        wavonbtn.addEventListener( "click", swap2mp3, false ) ;
        mp3offbtn.addEventListener("click", swap2mp3, false ) ;

        showpl.addEventListener("click", showPlaylist) ;

    // playlist elements -
    // Create function variables to use for  click & double-click
            var loadFile = function() {
                var peg = this.getAttribute("peg") ;
                pauseAudio()                    ;
                initAudio(peg)                  ;
            };

            var playFile = function() {
                var peg = this.getAttribute("peg") ;
                pauseAudio()                    ;
                playing = 1                     ;
                initAudio(peg)                  ;          
            };  
    // Add Click and Double-Click evnts to the wav List Items  
        var wavLI = document.getElementsByClassName('wavItem')  ;        
        for (tick = 0; tick < wavLI.length; tick++) {
            wavLI[tick].addEventListener('click',    loadFile, false)   ;
            wavLI[tick].addEventListener('dblclick', playFile, false)   ;
        }
        
    // Add Click and Double-Click evnts to the mp3 List Items        
        var mp3LI = document.getElementsByClassName('mp3Item')  ;        
        for (tick = 0; tick < mp3LI.length; tick++) {
            mp3LI[tick].addEventListener('click',    loadFile, false)   ;
            mp3LI[tick].addEventListener('dblclick', playFile, false)   ;
        }           
      
    // initialization - first element in playlist
        initAudio( 0 ) ;       

        InitProgress("songbar") ;
        InitProgress("volume" ) ; 

        SetProgress("songbar", 0 ) ;
        SetProgress("volume", 80 ) ;
        audio.volume = 0.8 ;

    //Start KBSlider functions for Volume:
        setSliderDrag("volume") ;  

}) ;


The Client-Side: JS - specific for the sliders

(This is a modified version of the KBSlider - dynamic slider control)
dPlayer GUI-Sliders JS SOURCE CODE:
>Show More<
/***********************************************
 *  ~~ KBSliderX.js  V 4.3.4  ~~
 *
 *  Part of - KBSlider Project -
 *  Complete Div based /CSS/JS range slider
 *  (Not using HTML Input)
 *
 *  Copyright Kirk Siqveland 2022
 *
 *
 ***********************************************

    KBSlider provides Range-Slider function using only js, css and html
    without jQuery or any external PHP code.
    The demo CSS file does use PHP to simplify customization but the
    CSS code can be used from a simple CSS file if desired.

    This js file inserts the whole slider into your html file using
    an empty div with the class "KBSlider" and an id you use to 
    identify how it will be used, e.g.:

    <div class="KBSlider" id="volume" button="none"></div>

    Note: the "button" attribute flags whether to show progress on the
    slider button. The two options are "display" and "none"

    If there is a div with the class "feedback" we will use that to 
    display the progress in text as a Percent of progress along the slider.
    Code could be modified to use different increments.

 **/


 /*  TO USE : add code to your own JavaScript file, something like:

    document.addEventListener("DOMContentLoaded", function() {

       //Start KBSlider functions for Volume Slider:
          InitProgress("volume" )     ; // This inserts the Slider into the HTML based on a div with 
                                        // in this example:   <div class="KBSlider" id="volume" ></div>
          SetProgress( "volume", 80 ) ; // set the progress display to 80%
       setSliderDrag(  "volume" )     ; // activates the interactive functions (click, slide, drag)

    }) ;

*/


/*\ 
  EXTERNAL JS USAGE EXAMPLE:

     SetProgress(SliderID, pegProgress)                        // programatically Set Slider in Percent                     
     InitProgress(SliderID, minUnit=0, maxUnit=100, Step=1, BtnShift=2)     // Initialize Slider  Range
\*/  



  /*\*****   Template Call-Back: Insert your response to Changes from any Slider  ****\*****/
 /***\****        assign the slider and id in the html  e.g. id="volume";         *****\***/
/*****\***       Your primary js file should contain the Callback function        ******\*/

//     function KBSliderCallBack(ID, setProgress, setPixels = -1, maxPixels = -1){
//     // Add your Code to respond to slider Changes Here:
//         switch(ID){
//           case "volume":
//               audio.volume = setProgress/100 ;
//               break ;
//           case "songbar": 
//               audio.currentTime = setTime ; 
//               break ;
//         }
//     }    


var BtnShift   = -2 ; // adjust (usually negative number) to shift drag-button


/* ====================================================================== */
/*              G E N E R A L   P O S I T I O N I N G :                   */
/* ====================================================================== */

var DeBounce ;
var SliderSet = ["empty"]; // collection of all sliders in this document


/* ====================================================================== */
/*            B A S E   M O U S E   W H E E L   S T E P S                 */
/* ====================================================================== */
  var dyOpera =  40 ;       // Opera
  var dyFfox  =   3 ;       // Firefox;         
  var dyW3    = 120 ;       // IE/Safari/Chrome 
    if((navigator.userAgent.toLowerCase()).indexOf("mac os x")> 0){
        dyFfox  =   1 ;     // Firefox;        
        dyW3    =   3 ;     // IE/Safari/Chrome    
    }
 
/* ==================  set Position Slider by Percent  ================== */
    function SetProgress(ID, pegProgress){ 
        let  Slider  = "slider_" + ID  
        // console.log("SetProgress = "+Slider) ;
        window[Slider].Progress =  pegProgress                    ;
        window[Slider].ProgBar.style.width   =  pegProgress + "%" ;
        window[Slider].DragFrame.style.left  = (pegProgress - window[Slider].Offset) + "%" ;
        // window[Slider].title  = pegProgress + "%";
    }   

/* ==================  Position Slider by Pixels  ===================== */
    function setSlider(ID, pegWidth){    
      let Slider = "slider_"+ID                                 ;
        let testMax = window[Slider].maxVal                     ;
          if( pegWidth < 0 ){            pegWidth = 0           ;
          }else if(pegWidth > testMax){  pegWidth = testMax     ;}
        let pegProgress = Math.floor( pegWidth/testMax*100 )    ;

        window[Slider].Progress = pegProgress                     ;
        window[Slider].ProgBar.style.width   =  pegProgress + "%" ;
        window[Slider].DragFrame.style.left  = (pegProgress - window[Slider].Offset) + "%" ;                

      showString(ID, pegProgress)  ;
      KBSliderCallBack(ID, pegProgress) ;
    }

/* =========  Position Slider by Percent / or Tick Marks  ============== */
    function tapSlider(ID, pegShift){
      let Slider        = "slider_"+ID                          ;
        let testMax     = window[Slider].maxVal                   ;
        let pegProgress = window[Slider].Progress + pegShift      ;
          if(pegProgress < 0){          pegProgress =   0       ; 
          }else if(pegProgress > 100){  pegProgress = 100       ; }
  
        window[Slider].Progress = pegProgress                     ;
        window[Slider].ProgBar.style.width   =  pegProgress + "%" ;
        window[Slider].DragFrame.style.left  = (pegProgress - window[Slider].Offset) + "%" ;  

      showString(ID,pegProgress)                         ;
      KBSliderCallBack(ID, pegProgress) ;
    }    


/* =========  Position Slider with Mouse-Wheel Change  ==================== */
    function wheelMove(event){      
      let wheelid = document.activeElement.parentNode.id ;
      if (SliderSet.indexOf(wheelid) >= 0){

          if (!event) event = window.event     ;
            //flac needed to block page scroll
              event.preventDefault()           ;  
              event.stopPropagation()          ;
              event.stopImmediatePropagation() ;

        var delta=0, radDelta=event.wheelDelta, radDetail=event.detail ;
          if (radDetail){
            if (radDelta) return radDelta/dyOpera>0?1:-1 ;      // Opera
            else delta = -radDetail/dyFfox               ;      // Firefox;         
          } else delta =  radDelta/dyW3                  ;      // Chrome/IE/Safari        

          if(event.shiftKey){ 
                 delta = delta * 15 ; 
          }else{ delta = delta *  3 ; }

          tapSlider(wheelid, delta) ;

          //more flac to block page scroll
          event.returnValue = false;
          return false;
      } 
    }  

/* =============  Display Messages if desired  ================== */
    function showString(ID, msg, progSymbol = "%"){
      let thisSlider = document.getElementById(ID) ;
      thisSlider.querySelector(".fbDump ").innerHTML = msg+progSymbol ;
      thisSlider.querySelector(".dragbtn").innerHTML = msg+progSymbol ;
    }

/* ===========  Responsive / Dynamic Resize  ====================  */
    function resizeMe(){
        for (let tick = 1; tick < SliderSet.length; tick++){ 
          let Slider = "slider_"+SliderSet[tick];          
          window[Slider].setMaxVal();
        }
    }


/* ====================================================================== */
/*          P R O G R E S S   C H A N G E   M E T H O D S :               */
/* ====================================================================== */
// Called from js file controlling the slider for your app

function InitProgress(myID, minUnit=0, maxUnit=100, Step=1, BtnShift=2){
  /** e.g.   InitProgress("volume" ) ;     **/
    let Slider = "slider_" + myID ;
      console.log("InitSlider: "+Slider) ;

    SliderSet.push(myID) ;
    let thisSlider  = document.getElementById(myID) ;
    if( newSlider  = null){
      console.log ("failed to find slider "+myID) ;
      return ;
    }

    /**  INJECT the Slider Components   **/
      let addHTML   = '<div class="progbox" tabindex="0"><div class="progbar" >' ;
        addHTML     = addHTML+'<div id="mydragframe" class = "dragframe">'       ;
        addHTML     = addHTML+'<div id="mydragbtn"   class = "dragbtn">'         ;
        addHTML     = addHTML+'</div></div></div></div>'                         ;
        addHTML     = addHTML+'<div class="fbDump"></div>'                       ;
      thisSlider.innerHTML = addHTML ;

        let myprogbox = thisSlider.querySelector(".progbox")   ;
        let dragframe = thisSlider.querySelector(".dragframe") ;
        let dragbox   = dragframe.getBoundingClientRect()      ;        
        let dragbtn   = thisSlider.querySelector(".dragbtn")   ;
          if(thisSlider.getAttribute("button") !== ("display"||"Display"))
          {  dragbtn.classList.add("hidden")                   ; }        
        
        window[Slider] = { } ; //Declare a global variable collection

        // Assign values to the new collection
          window[Slider].ID        = myID ;
          window[Slider].ProgBox   = thisSlider.querySelector(".progbox")   ;
          window[Slider].ProgBar   = thisSlider.querySelector(".progbar")   ;
          window[Slider].DragFrame = thisSlider.querySelector(".dragframe") ; 
          window[Slider].Duration  =   0 ;
          window[Slider].Progress  =   0 ;
          window[Slider].minVal    =   0 ; 
          window[Slider].BtnShift  = BtnShift ;       
          window[Slider].minUnit   = minUnit  ;
          window[Slider].maxUnit   = maxUnit  ;  
          window[Slider].Step      = Step     ;
            window[Slider].setMaxVal = function () {
              let thisslider = document.getElementById(this.ID)                   ;
                this.maxVal  = (thisslider.querySelector(".progbox").getBoundingClientRect().width) ;
                this.Unit    = this.maxVal/(maxUnit-minUnit)                      ;
                this.Offset  = parseInt( ((dragbox.width/2)+BtnShift)/this.Unit ) ;
                this.ProgBar.style.width   =  this.Progress + "%" ;
                this.DragFrame.style.left  = (this.Progress - this.Offset) + "%" ;
            };
          window[Slider].setMaxVal() ;

        // console.log("InitProgress maxVal: "+window[Slider].maxVal+" - Unit: "+window[Slider].Unit+" - Offset: "+window[Slider].Offset ) ;

        /* ------ Click and Focus Event Listeners ----- */

        myprogbox.addEventListener("click", function(e){  
            let BCR  = this.getBoundingClientRect()      ;
            let peg  = (e.clientX - BCR.left)            ;
            let myID = this.parentNode.id ;
            this.style.opacity = "1"   ;
            // this.focus();
            setSlider(myID, peg) ;
        });

        myprogbox.addEventListener('focus', function() {
            this.style.opacity = "1"   ;
        });
        myprogbox.addEventListener('focusout', function() {
            this.style.opacity = "0.8" ;
        });
        myprogbox.addEventListener('mouseover', function() {
            this.focus() ;
            // this.title = this.parentNode.id;
            let progBar = this.querySelector('.progbar');
            this.title  = parseInt((progBar.clientWidth / this.clientWidth||0)*100)+'%';
        });
        myprogbox.addEventListener('mouseout', function() {
            let Slider = "slider_" + this.parentNode.id ;
        });

    /* ==============  Keyboard Responses  ==================== */
        myprogbox.addEventListener('keydown', function(e) {
          /**    myID = this.parentNode.id ;        */
            // console.log("Keycode Down: " + e.keyCode) ;
            switch (e.keyCode) {
                // case 16: // Shift-Key
                //     shiftKey = true ;
                //     break ;
                case 35: // End-Key
                    tapSlider(myID, 100) ;
                    break ;
                case 36: // Home-Key
                    tapSlider(myID, 0) ;
                    break ;             
                case 37: // Arrow-Key Left
                    if(e.shiftKey){
                      tapSlider(myID, - 10) ;
                    }else{
                      tapSlider(myID, - 1) ;
                    }
                    break ;
                case 38: // Arrow-Key Up
                    if(e.shiftKey){
                      tapSlider(myID, - 10) ;
                    }else{
                      tapSlider(myID, - 1) ;
                    }
                    break ;                
                case 39: // Arrow-Key Right
                    if(e.shiftKey){
                      tapSlider(myID, + 10) ;
                    }else{
                      tapSlider(myID, + 1) ;
                    }
                    break ;
                case 40: // Arrow-Key Down
                    if(e.shiftKey){
                      tapSlider(myID, + 10) ;
                    }else{
                      tapSlider(myID, + 1) ;
                    }
                    break ;   
            }  /*/ -end-  Switch      /*/
        }); /*/ -end- Keydown     /*/
} /*/ -end- InitProgress   /*/


/* ====================================================================== */
/*          D R A G - T O U C H  M E T H O D S  :                         */
/* ====================================================================== */

/*    The Whole Drag/Touch-Process Bundled into One Function   */
    function setSliderDrag(sliderID) {
      let thisSlider = document.getElementById(sliderID)     ;             

      let progbox   = thisSlider.querySelector(".progbox")   ;
      let dragframe = thisSlider.querySelector(".dragframe") ;
      let currrect  = progbox.getBoundingClientRect()      ;
      let minUnit   = currrect.left                        ;
      let maxUnit   = currrect.left  + currrect.width      ;

      dragframe.onmousedown  = StartSliderDrag ;
      dragframe.ontouchstart = StartSliderPush ;       


    /* =========== Slider Mouse on Button Response ==================== */

      /**        Start a Drag sequence...        **/
        function StartSliderDrag(e) {
          // console.log("StartSliderDrag myID =  "+myID ) ;
            (e || window.event).preventDefault()                ;
            DeBounce = true ;

          /** set functions on MouseMove or MouseUp: */
            document.onmousemove  = sliderBtnDrag     ;
            document.onmouseup    = closeDragBtn      ;
        }

      // Show Drag Motion on document.mousemove
        function sliderBtnDrag(e) {   
          /** trim responses to parallel X to ProgBox */
          if(e.clientX>minUnit && e.clientX<maxUnit){ 
              (e || window.event).preventDefault()     ;
            /** calculate the new cursor position:    */
              let DragDelta = (e.clientX - minUnit)    ;
            /** set the element's new position:       */
              setSlider(sliderID, DragDelta )          ;
          }
        }

      // Finish a Drag Sequence (touch or mouse)
        function closeDragBtn() {
          /** stop moving when mouse button is released: */
              DeBounce = false            ;
              document.onmouseup   = null ;
              document.onmousemove = null ;
        }


    /* =========== Touch Slider Response ==================== */

        function StartSliderPush(e) {
          (e || window.event).preventDefault()    ;
            DeBounce = true ;
          /**  call function on Touch:  */
            document.ontouchmove  = sliderBtnPush ;        
            document.ontouchend   = EndSliderPush ;  
            document.ontouchcancel= EndSliderPush ;        
        }    
        function sliderBtnPush(e) {
            (e || window.event).preventDefault()  ;
          if(e.touches[0].clientX>minUnit&&e.touches[0].clientX<maxUnit){
            let DragDelta = (e.touches[0].clientX - minUnit) ;
            /** set the element's new position:       */
              setSlider("volume", DragDelta )     ;
          }
        }
        function EndSliderPush(e) {
            DeBounce = false             ;
            document.ontouchmove  = null ;        
            document.ontouchend   = null ;  
            document.ontouchcancel= null ;         
        }    
    } /*/ -end-  setSliderDrag() /*/



/* ================ Last Job : add Window Event Listeners =============== */

  window.onresize = resizeMe ;

  window.addEventListener('DOMMouseScroll', wheelMove, {passive: false}) ;  // Declared deprecated but 'wheel' does not work!
  window.addEventListener('mousewheel',    	wheelMove, {passive: false}) ;  // Declared deprecated but 'wheel' does not work!
  //window.addEventListener('wheel', wheelMove, {passive: false} ) ;


/* ====================================================================== */





The CSS - Style code:

(This works with a single specific image to provide the transports and other controls)
dPlayer CSS SOURCE CODE:
>Show More<
/*
        ~ dPlayer.css ~ 

    Style definitions for dPlayer: HTML5 dynamic Audio-file Player;

    Includes Style Configuration for KBSlider / KBSliderX Range-Slider
    ( See Bottom and Note Style vs Function Settings when customizing )

*/

* {
    margin:     0 ;
    padding:    0 ;
}
body {
    background-color: transparent ;
}
header {
    background-color:rgba(33, 33, 33, 0.9) ;
    font: 14px/1.3 Arial,sans-serif;
    margin-bottom: 10px     ;
    position:relative       ;
    display:block           ;
    color:#fff              ;
}
header h2{
    font-size:   22px       ;
    margin:       0px auto  ;
    padding:     10px 0     ;
    width:       80%        ;
    text-align:  center     ;
}
header a, a:visited {
    text-decoration: none     ;
    color:           #fcfcfc  ;
}

#debugger { ; }

.centerbox {
    margin: 0 auto 0                ;
    width: 350px                    ;
    background-color: transparent   ;
    height: 100%                    ;
}
.RightText {
    text-align: right               ;
}
.player {
    background: transparent url("dPlayer.png") no-repeat scroll center top;
    height: 180px               ;
    position: relative          ;
    width: 350px                ;
    z-index: 2                  ;
}
.title, .album, .subtitle {
    font-family: verdana        ;
    left: 10px                  ;
    position: absolute          ;

    -moz-user-select: none      ;
    -webkit-user-select: none   ;
    -ms-user-select: none       ;
}
.title {
    color: #FFFFFF      ;
    font-size: 14px     ;
    font-weight: bold   ;
    top: 6px            ;
    white-space: nowrap ;
    max-width: 331px    ;
    overflow: hidden    ;
}
.subtitle {
    font-style: italic  ;
    color: #EEEEEE      ;
    font-size: 12px     ;
    top: 28px           ;
    max-width: 335px    ;
    overflow: hidden    ;
}
.album {
    color: #EEEEEE      ;
    font-size: 12px     ;
    top: 44px           ;
}
.pl {
    background: transparent url("dPlayer.png") no-repeat scroll -264px -194px;
    cursor: pointer    ;
    height: 40px       ;
    left: 285px        ;
    position: absolute ;
    top: 110px         ;
    width: 45px        ;
}
.pl:hover {
    top: 111px ;
}
.cover {
    background: transparent url(CoverThumb.jpg) no-repeat scroll center top;
    border-radius:  5px 5px 5px 5px;
    height:         94px    ;
    left:           10px    ;
    position:       absolute;
    top:            71px    ;
    width:          94px    ;
}
#splash{ 
    border: none ;
    border-radius:  5px 5px 5px 5px;    
    height: 100% ;
    width:  100% ;
}
.controls {
    cursor:   pointer  ;
    height:    25px    ;
    left:     150px    ;
    position: absolute ;
    top:       72px    ;
    width:    180px    ;
}
.toggles { 
    cursor:     pointer  ;
    height:      23px    ;
    left:       160px    ;
    position:   absolute ;
    top:        105px    ;
    width:      100px    ;
}

.controls .play, .controls .pause, .controls .prev, .controls .rew, .controls .fwd {
    background: transparent url("dPlayer.png") no-repeat scroll 0 0;
    float:  left        ;
    height: 100%        ;
    width:   45px       ;
}

.toggles .mp3on, .toggles .mp3off, .toggles .wavon, .toggles .wavoff {
    background: transparent url("dPlayer.png") no-repeat scroll 0 0;
    float:  left       ;
    height: 100%       ;
    width:   48px      ;
}

.toggles .mp3on  {
    background-position: -54px -212px  ;
}
.toggles .mp3off {
    background-position: -101px -212px ;
}
.toggles .wavon  {
    background-position: -148px -212px ;
}
.toggles .wavoff {
    background-position: -197px -212px ;
}


.controls .play {
    background-position: -8px -187px   ;
}
.controls .pause {
    background-position: -8px -214px   ;
    display: none;
}
.controls .prev {
    background-position: -53px -187px  ;
}
.controls .rew {
    background-position: -98px -187px  ;
}
.controls .fwd {
    background-position: -143px -187px ;
}


.controls .play:hover {
    background-position: -9px -186px   ;
}
.controls .pause:hover {
    background-position: -9px -213px   ;
}
.controls .prev:hover {
    background-position: -54px -186px  ;
}
.controls .rew:hover {
    background-position: -99px -186px  ;
}
.controls .fwd:hover {
    background-position: -144px -186px ;
}

.controls .visible, .toggle .visible {
    display: block       ;
}

#volume {
    height:       8px    ;
    left:       150px    ;
    position:   absolute ;
    top:        135px    ;
    width:      116px    ;
}
#songbar{
    display:    inherit     ;
    position:   absolute    ;
    height:     15px        ;
    top:        153px       ;
    left:       150px       ;
    width:      181px       ;
    cursor:     pointer     ;
}
.mp3list, .wavlist {
    background-color: #333333;
    border-radius: 0px 0px 5px 5px;
    list-style-type: none   ;
    margin: -10px 0 0 2px   ;
    padding-bottom: 10px    ;
    padding-top: 15px       ;
    padding-right: 15px     ;
    position: relative      ;
    width: 316px            ;
    z-index: 1              ;
}
.mp3list li, .wavlist li {
    color: #EEEEEE          ;
    cursor: pointer         ;
    margin: 0 0 5px 15px    ;
}
.mp3list li.active, .wavlist li.active {
    font-weight: bold       ;
    color:#FFFFCC           ;
}

  /*\--------------------------------\*-*-*/
 /***\ -  S L I D E R - S T Y L E  -  \* */
/*-*-*\--------------------------------\*/ 

div#volume .progbox{
  border-radius:  2px 2px 2px 2px;
}  
div#volume .progbox:focus { outline: 0; }

div#volume .progbar{
  height: 8px ;
  border-radius:  2px 0 0 3px ;
  background: transparent url("dPlayer.png") no-repeat scroll 0px -240px ;
}
div#volume .dragframe{  
  text-align: center ;
  min-height: 13px   ;
  min-width:  13px   ;
  background: url("Loud.png"); 
  background-size: cover ;     
  top: -2px          ;
}
div#volume .dragbtn{
  padding: 3px    ;
  color: #fff     ;
}


div#songbar .progbox{
    display:    inherit  ; 
    height:     100%     ;
    width:      100%     ;
}  
div#songbar .progbox:focus { outline: 0; }

div#songbar .progbar{
    display:    inherit     ;
    background: transparent url("dPlayer.png") no-repeat scroll 0px -240px;
    height:     15px        ;
    position:   absolute    ;
    top:        0           ;
    left:       0           ;
    border-radius:  2px 2px 2px 2px ;     
}
div#songbar .dragframe{  
    display: none   ;
}
div#songbar .dragbtn{
    display: none   ;
}

  /*\---------------------------------------\*-*-*/
 /***\  -  S L I D E R - F U N C T I O N  -  \* */
/*-*-*\---------------------------------------\*/


.KBSlider{
  display: inherit ;
}

.progbox{
  position: absolute  ;
  width: 100%         ;
  z-index: 7          ;
  /*top: 10px ;*/
} 

.progbar{
  z-index:      8  ;
}

.dragframe{  
  position: absolute     ; 
  background-size: cover ;  
  z-index: 10            ;
}

.dragbtn{  
  display: inline ;  
  cursor: pointer ;  
  z-index: 9      ;
}


.hidden { display: none ; }
.fbDump { display: none ; }
.nojsmsg{
    text-align: center;
}



The image files:

The CSS extracts various controls(Transports) from this image, so any change can cause problems.

This image is © Kirk Siqveland 2022, released under the same Creative Commons license as the rest of the dPlayer Code.


This is just a place-holder in-case no album cover or song image exists.

This image is used for the volume slider:

Or if you like here is the Volume image in SVG format:

Both Volume images have been contributed to the public Domain.


KBSlider dPlayer and all related Source-Code
Copyright © 2022 by Kirk Siqveland
Under CC-BY-NC-SA 4.0