Skip to main content

PowerShell : Play Music until Sleep

A while back I had blogged about using PowerShell to create a playlist of random songs in VLC player & I had a rudimentary function based on that in my profile.


001
002
003
004
005
006
function play-song
{
    param([int]$count=5, [string]$Path="D:\Songs")
    Get-ChildItem $Path -recurse -filter *.mp3| Get-Random -Count $count |
        ForEach-Object -process { Start-Process $_.Fullname -verb 'AddtoPlaylistVLC'}
}

I know the name contains an unapproved verb but I was lazy to change it.


Few days back I thought of extending above function a little bit, so that my laptop Sleeps when the songs in the playlist end (hopefully I would have slept by that time )


I took a simple approach for this: 

  • Get the total duration of all the songs 
  • Create a Job Trigger with current time + duration of the songs + 1 minute
  • Create a PowerShell Scheduled job which will sleep the machine 

Below is the explanation of the code :

First let's take a look at the Function definition & the parameters declared.


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
function Start-VLCplaylist
 {
     [CmdletBinding()]
     Param
     (
         # Specify the folder path where Music files are stored
         [Parameter(ValueFromPipeline,
                    ValueFromPipelineByPropertyName)]
         $Path='D:\Songs', #Putting a default value here so that I don't have to specify it everytime

         # Specify the count of songs to play
         [Parameter()]
         [int]$count=5,

         #Specify this switch if you want your System to sleep after songs in the playlist get over
         [Switch]$SleepLater
     )


  • Name of the Function has approved Verb now.
  • Path parameter to tell where you have your all .mp3 files stored.
  • Count param to tell how many songs to add to playlist.
  • SleepLater Switch to tell the function to sleep the computer after all songs have played.
Now Let's proceed to the Begin {} block


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
Begin
     {
       Write-Verbose -Message '[Start-VLCplaylist] Begin : Starting the Function'
       if (Test-Path -Path 'C:\Program Files (x86)\VideoLAN\VLC\vlc.exe' -PathType Leaf)
       {
           #Associate the .MP3 files to be open with VLC
           $null = cmd /c 'assoc .mp3=VLC.mp3'
           $null = cmd /c 'ftype VLC.mp3="C:\Program Files (x86)\VideoLAN\VLC\vlc.exe" --started-from-file "%1"'
           Write-Verbose -Message '[Start-VLCplaylist] Begin : .MP3 files associated to be open with VLC player'
       }
       else
       {
            Throw 'VLC Player is not installed'
       }
       $shell = New-Object -COMObject Shell.Application
       $duration = [timespan]::Zero
     }


  • Check if VLC player is installed. If not throw an exception.
  • Use Assoc & Ftype to associate .mp3 files to VLC player.
  • Create a Shell.Application COM Object for later use.
  • Variable duration to store the total duration of the songs, initialized to Zero.

Time for the  Process {} Block.


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
Process
     {
        Write-Verbose -Message '[Start-VLCplaylist] Process : Randomly collecting the songs'
        $Songs = Get-ChildItem -Path $Path -recurse -Filter *.mp3| Get-Random -Count $count
      
        ForEach ($song in $Songs)
        {
      
            $shellfolder = $shell.Namespace($($song.directoryname))
            $shellfile = $shellfolder.ParseName($($Song.Name))
            $Duration = $duration +  [timespan]$($shellfolder.GetDetailsOf($shellfile, 27))
            Write-Verbose -Message "[Start-VLCplaylist] Process : Working with $($song.name) ; Totalduration : $($duration.TotalMinutes)"
            Start-Process $song.Fullname -verb 'AddtoPlaylistVLC'
      
       
        }
        If ($SleepLater)
        {
            Write-Verbose -Message '[Start-VLCplaylist] Process : Creating the Trigger for the Scheduled Job'
            $trigger = New-JobTrigger -Once -At $( (Get-Date).AddMinutes($duration.TotalMinutes + 2))
      
            $joboption = New-ScheduledJobOption -HideInTaskScheduler -ContinueIfGoingOnBattery

            if (Get-ScheduledJob -Name DexSleepAfterMusic)
            {
                Write-Verbose -Message '[Start-VLCplaylist] Process : The Scheduled Job DexSleepAfterMusic already exists. Setting the Trigger & job option'
                Get-ScheduledJob -Name DexSleepAfterMusic | Set-ScheduledJob  -Trigger $trigger
            }
            else
            {
                Write-Verbose -Message '[Start-VLCplaylist] Process : Creating the Scheduled Job DexSleepAfterMusic '
                Register-ScheduledJob -Name DexSleepAfterMusic -ScriptBlock {[System.Windows.Forms.Application]::SetSuspendState($([System.Windows.Forms.PowerState]::Suspend), $false, $false)} `
                    -Trigger $trigger -ScheduledJobOption $joboption
                #Schedule the system to sleep in
            }   
  
        }
     }
     End
     {
        Write-Verbose -Message '[Start-VLCplaylist] End : Ending the Function'
     }

  • Randomly select the songs.
  • Foreach Song - use the COM Object to get the duration (add it to $Duration) & add the song to the playlist
  • If Switch SleepLater is specified then Create a Job Trigger by adding the totalminutes of the duration + 1 minute to the current time.
  • Create a new job option which hides the Scheduled Job in Task Sched & run even if on battery.
  • Check if the Scheduled Job is already created if Yes then just set the Trigger & Job option (Just to be sure)
  • If the Scheduled Job was not created earlier go ahead and create it.
Note - The Scriptblock used will Sleep the machine once the total duration of the songs is over.

The Function right now only works with the .Mp3 files but you can very well make it work with Video files etc.

Below is a gif showing it in action :)


Listening to music and going to sleep now ;)
P.S - At the end I disabled the Scheduled Job so that my Machine doesn't sleep while I am working (after the Playlist gets over) :)


Resources :

MVP Trevor's response @ Stack Overflow to sleep or hibernate machine
http://stackoverflow.com/questions/20713782/suspend-or-hibernate-from-powershell

PowerShell.com - Organize Videos and Music 
http://powershell.com/cs/blogs/tobias/archive/2011/01/07/organizing-videos-and-music.aspx



Popular posts from this blog

Test connectivity via a specific network interface

Recently while working on a Private cloud implementation, I came across a scenario where I needed to test connectivity of a node to the AD/DNS via multiple network adapters.  Many of us would know that having multiple network routes is usually done to take care of redundancy. So that if a network adapter goes down, one can use the other network interface to reach out to the node. In order to make it easy for everyone to follow along, below is an analogy for the above scenario: My laptop has multiple network adapters (say Wi-Fi and Ethernet) connected to the same network. Now how do I test connectivity to a Server on the network only over say Wi-Fi network adapter?

PowerShell + SCCM : Run CM cmdlets remotely

Today I saw a tweet about using implicit remoting to load the Configuration Manager on my machine by Justin Mathews . It caught my eye as I have never really tried it, but theoretically it can be done. Note - The second tweet says "Cannot find a provider with the name CMSite", resolution to which is in the Troubleshooting section at the end.

Azure DevOps Tips & Tricks - Find private REST APIs

Original source -  Azure DevOps Tip - Find private APIs Often working with Azure DevOps, I hit a wall trying to automate some tasks but there are no REST API's made public yet. It was one of those task of automating creation of Environments in multi-stage YAML based pipelines in AzDO. Quick research reveals that this has been requested in uservoice  (please upvote). Let's see one of the very simple ways to discover some of these APIs.