Thank you for your donation!


Cloudsmith graciously provides open-source package management and distribution for our project.


One button / command to load & play random track?
#11
(02-26-2019, 03:25 PM)tristanc Wrote: What do you think?

This oneliner add 3 random songs from library to current playlist and play the first one.
Code:
mpc listall | shuf -n3 | mpc -q add && mpc play $(expr $(mpc playlist | wc -l) - 2)

You can create function (or script):
Code:
function rta() {
 if [ -z "$1" ]; then
  n="1"
 else
  n="$1"
 fi
 mpc listall | shuf -n "$n" | mpc -q add
 (( n-- ))
 mpc play $(expr $(mpc playlist | wc -l) - "$n" )
}

"rta n" adds n random tracks and play the first one.
Reply
#12
(03-03-2019, 12:45 PM)tristanc Wrote: So this code is a really inefficient way of getting close to what I described. This will 'click' on the 'random' button on the web interface from a (headless) remote machine. It uses Selenium and Chromium / chromedriver to run the web page in the background so things can be interacted with.

I've taken this and incorporated in to my GPIO button interface code - and so far works as I had hoped allowing me to go from a radio stream to random play (using ashuffle) and back again. Happy to share that code if people are interested.

In case anyone finds this in the future, I've had to update my code to work with v6. New version of my in-use code below.


Code:
#!/usr/bin/python3

from gpiozero import Button
from signal import pause
import requests
from systemd import journal
import time
from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument('headless')
options.add_argument('no-sandbox')
options.add_argument('"window-size=380,540"')
driver = webdriver.Chrome(chrome_options=options)

driver.get('http://moode-kitchen.local')

# Check GPIO Mappings - BCM numbering
radio4 = Button(26, True, None, 1, False)
jackfm = Button(16, True, None, 1, False)
#volup = Button(12, True, None, 1, False)
volup = Button(12, hold_time=2)
voldown = Button(13, True, None, 1, False)
toggleplay = Button(6, True, None, 1, False)
skip = Button(5, True, None, 1, False)

# Define the various functions needed
def play_radio4():
   journal.write("Play Radio4")
   radio4_response = requests.get('http://moode-kitchen.local/command/?cmd=playitagainsam.sh radio4')

def play_jackfm():
   journal.write("Play JackFM")
   jackfm_response = requests.get('http://moode-kitchen.local/command/?cmd=playitagainsam.sh jackfm')

def toggle_play():
   journal.write("Toggle")
   stop_response = requests.get('http://moode-kitchen.local/command/?cmd=playitagainsam.sh toggle')

def skip_track():
   journal.write("Skip")
   stop_response = requests.get('http://moode-kitchen.local/command/?cmd=playitagainsam.sh skip')

def vol_up():
   journal.write("Volume up")
   vol_up_response = requests.get('http://moode-kitchen.local/command/?cmd=vol.sh up 5')

def vol_down():
   journal.write("Volume down")
   vol_down_response = requests.get('http://moode-kitchen.local/command/?cmd=vol.sh dn 5')

def pressed():
   global press_time
   press_time = time.time()
   print("pressed at %s" % (press_time))
   
def released():
   release_time = time.time()
   pressed_for = release_time - press_time
#    print("released at %s after %.2f seconds" % (release_time, pressed_for))
   if pressed_for < volup.hold_time:
#        print("this is a short press")
       vol_up()

def random_play():
#    print("Random play selected")
   journal.write("Random play selected")
#    b = driver.find_element_by_id("random")
   b = driver.find_element_by_css_selector("html body.no-touch div.tab-content div#playback-panel.tab-pane.active div.container-playback.txtmid div.no-fluid div.span3 div#togglebtns.hide div.btn-group button.btn.btn-cmd.btn-toggle.random i.fal.fa-random")
   b.click()
       
def held():
#    print("this is a long press")
   stop_new_response = requests.get('http://moode-kitchen.local/command/?cmd=playitagainsam.sh stopclear')
#    toggle_play()
#    driver.save_screenshot('screenie.png')
   random_play()

#def exit_handler():
#    journal.write("Closing Chromium")
#    driver.close()
   
# Execute the functions on button presses / holds
radio4.when_pressed = play_radio4
jackfm.when_pressed = play_jackfm
#volup.when_pressed = vol_up
volup.when_pressed = pressed
volup.when_released = released
volup.when_held = held
voldown.when_pressed = vol_down
toggleplay.when_pressed = toggle_play
skip.when_pressed = skip_track

#atexit.register(exit_handler)

pause()


I've also had to tweak how the custom command is called (equivalent of vol.sh) as a change was made to the processing of the URLs. My version of /var/www/command/index.php is:


PHP Code:
<?php
require_once dirname(__FILE__) . '/../inc/playerlib.php';

playerSession('open''' ,'');
session_write_close();

if (isset(
$_GET['cmd']) && empty($_GET['cmd'])) {
    echo 
'Command missing';
}
// SH or PHP commands
elseif (stripos($_GET['cmd'], '.sh') !== false || stripos($_GET['cmd'], '.php') !== false) {
    
// check for valid chrs
 
   if (preg_match('/^[A-Za-z0-9 _.-]+$/'$_GET['cmd'])) {
        
// reject directory traversal ../
        
if (substr_count($_GET['cmd'], '.') > 1) {
            echo 
'Invalid string';
        }
        
// check for valid commands
 
       elseif (stripos($_GET['cmd'], 'vol.sh') !== false) {
 
          $result sysCmd('/var/www/' $_GET['cmd']);
 
          echo $result[0];
 
       }
 
       elseif (stripos($_GET['cmd'], 'playitagainsam.sh') !== false) {
 
          $result sysCmd('/var/www/' $_GET['cmd']);
 
          echo $result[0];
 
       }
 
       else {
 
           echo 'Unknown command';
 
       }
 
   }
 
   else {
 
       echo 'Invalid string';
 
   }
}
// MPD commands
else {
    if (
false === ($sock openMpdSock('localhost'6600))) {
        
$msg 'command/index: Connection to MPD failed';
        
workerLog($msg);
        exit(
$msg "\n");
    }
    else {
        
sendMpdCmd($sock$_GET['cmd']);
        
$result readMpdResp($sock);
        
closeMpdSock($sock);
        
//echo $result;
    
}

a duplicated section like the vol.sh part, but with my custom command file being matched instead.
Reply
#13
@tristanc

Where's there's a will, there's a way Smile

I like that you left markers on other threads to note that v6 requires mods. +1

Regards,
Kent
Reply


Forum Jump: