From d0b8d55c59d2f0358afb68e606148c5547e01f35 Mon Sep 17 00:00:00 2001 From: Wzut <> Date: Wed, 18 Jan 2017 20:29:28 +0000 Subject: [PATCH] 73_MPD.pm: add two new set commands : channelUp and channelDown, add new attr : unknown_artist_image, add new reading : playlist_num git-svn-id: https://svn.fhem.de/fhem/trunk@13144 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/73_MPD.pm | 157 +++++++++++++++++++++++++++++++------------- 1 file changed, 110 insertions(+), 47 deletions(-) diff --git a/fhem/FHEM/73_MPD.pm b/fhem/FHEM/73_MPD.pm index dbf5398d8..f3d0884db 100644 --- a/fhem/FHEM/73_MPD.pm +++ b/fhem/FHEM/73_MPD.pm @@ -21,6 +21,7 @@ # GNU General Public License for more details. ################################################################ +# Version 1.43 - 18.01.17 add channelUp and channelDown # Version 1.42 - 15.01.17 add Cover and playlist_json # Version 1.41 - 12.01.17 add rawTitle # Version 1.4 - 11.01.17 add mute, ctp, seekcur, Fix LWP:: , album cover @@ -87,6 +88,8 @@ my %sets = ( "clear_readings:noArg" => "", "mute:on,off,toggle" => "", "seekcur" => "", + "channelUp:noArg" => "", + "channelDown:noArg" => "", ); use constant clb => "command_list_begin\n"; @@ -109,7 +112,7 @@ sub MPD_Initialize($) $hash->{UndefFn} = "MPD_Undef"; $hash->{ShutdownFn} = "MPD_Undef"; $hash->{AttrFn} = "MPD_Attr"; - $hash->{AttrList} = "disable:0,1 password loadMusic:0,1 loadPlaylists:0,1 volumeStep:1,2,5,10 titleSplit:1,0 timeout waits stateMusic:0,1 statePlaylists:0,1 lastfm_api_key image_size:-1,0,1,2,3 cache artist_summary:0,1 artist_content:0,1 player:mpd,mopidy,forked-daapd ".$readingFnAttributes; + $hash->{AttrList} = "disable:0,1 password loadMusic:0,1 loadPlaylists:0,1 volumeStep:1,2,5,10 titleSplit:1,0 timeout waits stateMusic:0,1 statePlaylists:0,1 lastfm_api_key image_size:-1,0,1,2,3 cache artist_summary:0,1 artist_content:0,1 player:mpd,mopidy,forked-daapd unknown_artist_image ".$readingFnAttributes; $hash->{FW_summaryFn} = "MPD_summaryFn"; } @@ -140,6 +143,8 @@ sub MPD_updateConfig($) $hash->{".artist"} = ""; $hash->{".album"} = ""; $hash->{".playlist_crc"} = 0; + $hash->{helper}{playlistcollection}{val} = -1; + $hash->{".password"} = AttrVal($name, "password", ""); $hash->{TIMEOUT} = AttrVal($name, "timeout", 2); $hash->{".sMusicL"} = AttrVal($name, "stateMusic", 1); @@ -171,9 +176,16 @@ sub MPD_updateConfig($) } MPD_ClearReadings($hash); # beim Starten etwas aufräumen + readingsBeginUpdate($hash); + readingsBulkUpdate($hash,"playlist_json",""); + readingsBulkUpdate($hash,"playlist_num","-1"); + readingsBulkUpdate($hash,"playlistname",""); + readingsBulkUpdate($hash,"playlistinfo",""); + readingsBulkUpdate($hash,"playlistcollection",""); + readingsEndUpdate($hash,0); + MPD_Outputs_Status($hash); mpd_cmd($hash, clb.cle); - #MPD_NewPlaylist($hash,mpd_cmd($hash,"i|playlistinfo|x")); if ($hash->{".volume"} eq "0") { # ist Mute aktiv oder soll sie mit Absicht 0 sein ? @@ -239,17 +251,19 @@ sub MPD_Define($$) Log3 $name,3,"$name, Device defined."; readingsSingleUpdate($hash,"state","defined",1); - readingsSingleUpdate($hash,"playlist_json","",0); + $attr{$name}{devStateIcon} = 'play:rc_PLAY:stop stop:rc_STOP:play pause:rc_PAUSE:pause error:icoBlitz' unless (exists($attr{$name}{devStateIcon})); $attr{$name}{icon} = 'it_radio' unless (exists($attr{$name}{icon})); $attr{$name}{titleSplit} = '1' unless (exists($attr{$name}{titleSplit})); $attr{$name}{player} = 'mpd' unless (exists($attr{$name}{player})); - $attr{$name}{loadPlaylists} = '1' unless (exists($attr{$name}{loadPlaylists})); - #$attr{$name}{cache} = 'lfm' unless (exists($attr{$name}{cache})); - #$attr{$name}{loadMusic} = '1' unless (exists($attr{$name}{loadMusic})) && ($attr{$name}{player} ne 'mopidy'); + $attr{$name}{loadPlaylists}= '1' unless (exists($attr{$name}{loadPlaylists})); + $attr{$name}{unknown_artist_image} = '/fhem/icons/1px-spacer' unless (exists($attr{$name}{unknown_artist_image})); + #$attr{$name}{cache} = 'lfm' unless (exists($attr{$name}{cache})); + #$attr{$name}{loadMusic} = '1' unless (exists($attr{$name}{loadMusic})) && ($attr{$name}{player} ne 'mopidy'); + + #DevIo_CloseDev($hash); das wird irgendwann auch mal kommen ... :) - DevIo_CloseDev($hash); $hash->{DeviceName} = $hash->{HOST}.":".$hash->{PORT}; RemoveInternalTimer($hash); @@ -420,9 +434,9 @@ sub MPD_Set($@) if ($cmd eq "stop") { readingsBeginUpdate($hash); - readingsBulkUpdate($hash,"artist_image","/fhem/icons/1px-spacer"); + readingsBulkUpdate($hash,"artist_image",AttrVal($name,"unknown_artist_image","/fhem/icons/1px-spacer")); readingsBulkUpdate($hash,"artist_image_html",""); - readingsBulkUpdate($hash,"album_image","/fhem/icons/1px-spacer"); + readingsBulkUpdate($hash,"album_image",AttrVal($name,"unknown_artist_image","/fhem/icons/1px-spacer")); readingsBulkUpdate($hash,"album_image_html",""); readingsBulkUpdate($hash,"audio",""); readingsBulkUpdate($hash,"bitrate",""); @@ -443,11 +457,11 @@ sub MPD_Set($@) if ($hash->{STATE} eq "play") { readingsBeginUpdate($hash); - readingsBulkUpdate($hash,"artist_image","/fhem/icons/1px-spacer",1); - readingsBulkUpdate($hash,"artist_image_html","",1); - readingsBulkUpdate($hash,"album_image","/fhem/icons/1px-spacer",1); - readingsBulkUpdate($hash,"album_image_html","",1); - readingsBulkUpdate($hash,"Cover","",1); + readingsBulkUpdate($hash,"artist_image",AttrVal($name,"unknown_artist_image","/fhem/icons/1px-spacer")); + readingsBulkUpdate($hash,"artist_image_html",""); + readingsBulkUpdate($hash,"album_image",AttrVal($name,"unknown_artist_image","/fhem/icons/1px-spacer")); + readingsBulkUpdate($hash,"album_image_html",""); + readingsBulkUpdate($hash,"Cover",""); readingsEndUpdate($hash, 1); $ret = mpd_cmd($hash, clb."stop\n".cle); } @@ -455,24 +469,26 @@ sub MPD_Set($@) if ($cmd eq "previous") { - if (defined($hash->{READINGS}{"song"}{VAL}) > 0) + if (ReadingsNum($name,"song",0) > 0) { MPD_ClearReadings($hash); - $ret = mpd_cmd($hash, clb."previous\n".cle); + return mpd_cmd($hash, clb."previous\n".cle); } else { return undef; } } if ($cmd eq "next") { - if ($hash->{READINGS}{"nextsong"}{VAL} != $hash->{READINGS}{"song"}{VAL}) + if (ReadingsNum($name,"nextsong",0) != ReadingsNum($name,"song",0)) + #if ($hash->{READINGS}{"nextsong"}{VAL} != $hash->{READINGS}{"song"}{VAL}) { MPD_ClearReadings($hash); - $ret = mpd_cmd($hash, clb."next\n".cle); + return mpd_cmd($hash, clb."next\n".cle); } else { return undef; } } + if ($cmd eq "random") { my $rand = ($hash->{READINGS}{random}{VAL}) ? "0" : "1"; @@ -541,6 +557,7 @@ sub MPD_Set($@) if ($cmd eq "seekcur") { + $subcmd--; $subcmd++; # sicherstellen das subcmd numerisch ist $ret = mpd_cmd($hash,clb."seekcur $subcmd\n".cle); # ungetestet ! } @@ -564,23 +581,47 @@ sub MPD_Set($@) # den Rest als ein String $subcmd = join(" ",@a); + if ($cmd eq "channelUp") + { + my $i = ReadingsNum($name,"playlist_num",-1); + $i++; + if ($i <= $hash->{helper}{playlistcollection}{val}) + { + $cmd = "playlist"; + $subcmd = $hash->{helper}{playlistcollection}{$i}; + } + } + + if ($cmd eq "channelDown") + { + my $i = ReadingsNum($name,"playlist_num",0); + $i--; + if ($i > -1) + { + $cmd = "playlist"; + $subcmd = $hash->{helper}{playlistcollection}{$i}; + } + } + if ($cmd eq "playlist") { return "$name : no name !" if (!$subcmd); my $error; + my $nr = -1; MPD_ClearReadings($hash); $hash->{".music"} = ""; - #my $old_list = $hash->{".playlist"}; + $hash->{".playlist"} = $subcmd; # interne Playlisten Verwaltung readingsSingleUpdate($hash,"playlistname",$subcmd,1); $ret = mpd_cmd($hash, clb."stop\nclear\nload \"$subcmd\"\nplay\n".cle); - #if ($old_list ne $hash->{".playlist"}) - #{ - # brauchen wir das hier wirklich noch ? - #MPD_NewPlaylist($hash,mpd_cmd($hash, "i|playlistinfo|x|")); - #} - # + # welche Listen Nr ? + for (my $i=0; $i <= $hash->{helper}{playlistcollection}{val}; $i++) + { + $nr = $i if ($hash->{helper}{playlistcollection}{$i} eq $subcmd); + } + readingsSingleUpdate($hash,"playlist_num",$nr,1) if ($nr > -1); + my $json = ReadingsVal($name,"playlist_json",""); if ($json ne "") @@ -645,7 +686,7 @@ sub MPD_Set($@) mpd_cmd($hash, clb.cle) if ($subcmd ne "playlist"); shift @arr; - MPD_NewPlaylist($hash,join ("\n", @arr)) if (ReadingsVal($name,"playlist_json","") eq ""); + MPD_NewPlaylist($hash,join ("\n", @arr));# if ((ReadingsVal($name,"currentTrackProvider","Radio") eq "Radio") || (ReadingsVal($name,"playlist_json","") eq "")); return undef; } @@ -763,8 +804,8 @@ sub mpd_cmd($$) my $title = ""; my $exot = ""; my $rawTitle; - my $name = $hash->{NAME}; - my $playlists = $hash->{".playlists"}; + my $name = $hash->{NAME}; + my $old_plists = $hash->{".playlists"}; $hash->{VERSION} = undef; @@ -881,16 +922,16 @@ sub mpd_cmd($$) readingsEndUpdate($hash, 1 ); - if ((AttrVal($name, "image_size", -1) > -1) && (ReadingsVal($name,"playlist_json","") ne "")) + if (AttrVal($name, "image_size", -1) > -1) { MPD_get_artist_info($hash, urlEncode($artist)) if ($artist); MPD_get_album_info($hash, urlEncode($album)) if ($album); } - elsif (ReadingsVal($name,"playlist_json","") ne "") + if (ReadingsVal($name,"playlist_json","") ne "") { my $pos = ReadingsNum($name,"Pos",-1); - readingsSingleUpdate($hash,"Cover",$Cover[$pos],1) if($pos > -1); + readingsSingleUpdate($hash,"Cover",$Cover[$pos],1) if($pos > -1) && defined($Cover[$pos]); } } # Ende der Ausgabe Readings und Internals, ab jetzt folgt nur noch Bildschirmausgabe else @@ -924,13 +965,21 @@ sub mpd_cmd($$) print $sock "close\n"; close($sock); - if ($hash->{".playlists"} ne $playlists) # haben sich sich die Listen geändert ? + if ($hash->{".playlists"} ne $old_plists) # haben sich sich die Listen geändert ? { $hash->{".playlists"} =~ s/\n+\z//; - my $plists = $hash->{".playlists"}; - $plists =~ tr/\n/\:/; # Tablet UI will diese Art der Liste - readingsSingleUpdate($hash,"playlistcollection", $plists,1); - Log3 $name ,5 ,"$name, ".$hash->{READINGS}{"playlistcollection"}{VAL}; + $old_plists = $hash->{".playlists"}; + my @arr = split("\n",$old_plists); + my $i = 0 ;; + foreach (@arr) + { + $hash->{helper}{playlistcollection}{$i} = $_; + $i++; + } + $hash->{helper}{playlistcollection}{val} = $i-1; + $old_plists =~ tr/\n/\:/; # TabletUI will diese Art der Liste + readingsSingleUpdate($hash,"playlistcollection", $old_plists,1); + Log3 $name ,5 ,"$name, new playlistcollection -> $old_plists"; } return $output; # falls es einen gibt , wenn nicht - auch gut ;) @@ -1141,7 +1190,9 @@ sub MPD_try_idle($) } else { - Log3 $name, 4 , $name.", Idle Start failed, waiting $waits seconds for next try"; + my $error = "Idle Start failed, waiting $waits seconds for next try"; + Log3 $name, 4 , "$name, $error"; + readingsSingleUpdate($hash,"last_error",$error,1); RemoveInternalTimer($hash); InternalTimer(gettimeofday()+$waits, "MPD_try_idle", $hash, 0); return 0; @@ -1174,7 +1225,10 @@ sub MPD_watch_idle($) else { Log3 $name, 5 , $name.", idle PID ".$hash->{IPID}." found"; - if (($hash->{READINGS}{"presence"}{VAL} eq "present") && ($hash->{STATE} eq "play")) + if ((ReadingsVal($name,"presence","") eq "present") && + ($hash->{STATE} eq "play") && + (ReadingsVal($name,"currentTrackProvider","") ne "Radio") + ) { # Wichtig um das Readings elapsed aktuell zu halten (TabletUI) mpd_cmd($hash, "status"); @@ -1192,9 +1246,7 @@ sub MPD_get_artist_info ($$) my ($hash, $artist) = @_; my $name = $hash->{NAME}; return undef if (($hash->{'.artist'} eq $artist) || ($artist eq "")); - #my $playlistinfo = ReadingsVal($hash,"playlistinfo",""); - #Log3 $name,3,"$name play :".ReadingsVal($hash,"playlistinfo",""); - #MPD_NewPlaylist($hash,mpd_cmd($hash,"i|playlistinfo|x")) if (!$playlistinfo || ($playlistinfo eq "[]")); + $hash->{'.artist'} = $artist; my $data; my $cache = AttrVal($name,"cache",""); # default @@ -1273,6 +1325,7 @@ sub MPD_get_album_info ($$) } else # xml von lastfm holen { + $fname = $artist."_".$album.".xml"; Log3 $name ,4,"$name, new album $fname , getting file from lastfm"; HttpUtils_NonblockingGet($param); } @@ -1667,7 +1720,7 @@ sub MPD_NewPlaylist($$) for my $i (0 .. $#artist) { - $lastcover = "nan"; # default + $lastcover = AttrVal($name,"unknown_artist_image","/fhem/icons/1px-spacer"); # default if (defined($albumUri[$i])) { @@ -2010,6 +2063,8 @@ If you are using Mopidy with Spotify support you may also need LWP::UserAgent -> mpdCMD (cmd) => send a command to MPD Server ( MPD Command Ref )
mute => on,off,toggle
seekcur (time)
+ channelUp =>
+ channelDown =>

@@ -2055,6 +2110,7 @@ If you are using Mopidy with Spotify support you may also need LWP::UserAgent -> attr rg_artist room MPD
  • cache (default lfm => /fhem/www/lfm) store artist image and album cover in a local directory
  • +
  • unknown_artist_image => show this image if no other image is avalible (default : /fhem/icons/1px-spacer)

  • Readings @@ -2069,7 +2125,9 @@ If you are using Mopidy with Spotify support you may also need LWP::UserAgent -> currentTrackProvider : Radio / Bibliothek
    playlistinfo : (TabletUI Medialist)
    playlistcollection : (TabletUI)
    - playlistname : (TabletUI)
    + playlistname : (TabletUI) current playlist name
    + playlist_num : current playlist number
    + playlist_json : (Medialist Modul)
    rawTitle : Title information without changes from the modul @@ -2127,7 +2185,9 @@ If you are using Mopidy with Spotify support you may also need LWP::UserAgent -> IdleNow => sendet das Kommando idle zum MPD und wartet auf Ereignisse
    clear_readings => löscht sehr viele Readings
    mute => on,off,toggle
    - seekcur (zeit) => nicht vor MPD Version 0.20 + seekcur (zeit) => nicht vor MPD Version 0.20
    + channelUp =>
    + channelDown =>

    @@ -2179,7 +2239,7 @@ If you are using Mopidy with Spotify support you may also need LWP::UserAgent ->
  • cache (default lfm => /fhem/www/lfm) Zwischenspeicher für die XML und PNG Dateien
    Wichtig : Der User unter dem der fhem Prozess ausgeführt wird (default fhem) muss Lese und Schreibrechte in diesem Verzeichniss haben !
    Das Verzeichnis sollte auch unterhalb von www liegen, damit der fhem Webserver direkten Zugriff auf die Bilder hat.
  • - +
  • unknown_artist_image => Ersatzimage wenn kein anderes Image zur Verfügung steht (default : /fhem/icons/1px-spacer)

  • Readings @@ -2196,8 +2256,11 @@ If you are using Mopidy with Spotify support you may also need LWP::UserAgent -> artist_content : (bei Nutzung von Last.fm)
    artist_summary : (bei Nutzung von Last.fm)
    playlistinfo : (z.B. für die TabletUI Medialist)
    - playlistcollection : (TabletUI)
    - playlistname : (TabletUI)
    + playlistcollection : (TabletUI) Liste der Playlisten
    + playlistname : (TabletUI) Name der aktuellen Playliste aus playlistcollection
    + playlist_num : Playlisten Nr. (0 .. n) der aktuellen Playliste aus playlistcollection + playlist_json : (notwendig fü das Medialist Modul)
    + Cover : Cover Bild zum aktuellen Song aus playlist_json
    currentTrackProvider : Radio / Bibliothek - Unterscheidung Radio Stream oder lokale Datei
    rawTitle : Title Information ohne Veränderungen durch das Modul