diff --git a/api/base_api_controller.go b/api/base_api_controller.go
index d870a62e6..fca710d55 100644
--- a/api/base_api_controller.go
+++ b/api/base_api_controller.go
@@ -39,6 +39,10 @@ func (c *BaseAPIController) ParamString(param string) string {
 	return c.Input().Get(param)
 }
 
+func (c *BaseAPIController) ParamStrings(param string) []string {
+	return c.Input()[param]
+}
+
 func (c *BaseAPIController) ParamTime(param string, def time.Time) time.Time {
 	var value int64
 	if c.Input().Get(param) == "" {
@@ -74,6 +78,18 @@ func (c *BaseAPIController) ParamInt(param string, def int) int {
 	return value
 }
 
+func (c *BaseAPIController) ParamInts(param string) []int {
+	pStr := c.Input()[param]
+	ints := make([]int, 0, len(pStr))
+	for _, s := range pStr {
+		i, err := strconv.ParseInt(s, 10, 32)
+		if err == nil {
+			ints = append(ints, int(i))
+		}
+	}
+	return ints
+}
+
 func (c *BaseAPIController) ParamBool(param string, def bool) bool {
 	value := def
 	if c.Input().Get(param) == "" {
diff --git a/api/playlists.go b/api/playlists.go
index d632f522e..150869045 100644
--- a/api/playlists.go
+++ b/api/playlists.go
@@ -1,6 +1,8 @@
 package api
 
 import (
+	"fmt"
+
 	"github.com/astaxie/beego"
 	"github.com/deluan/gosonic/api/responses"
 	"github.com/deluan/gosonic/domain"
@@ -27,7 +29,7 @@ func (c *PlaylistsController) GetAll() {
 	for i, p := range allPls {
 		playlists[i].Id = p.Id
 		playlists[i].Name = p.Name
-		playlists[i].Comment = "Original: " + p.FullPath
+		playlists[i].Comment = p.Comment
 		playlists[i].SongCount = len(p.Tracks)
 		playlists[i].Duration = p.Duration
 		playlists[i].Owner = p.Owner
@@ -77,6 +79,32 @@ func (c *PlaylistsController) Delete() {
 	c.SendEmptyResponse()
 }
 
+func (c *PlaylistsController) Update() {
+	playlistId := c.RequiredParamString("playlistId", "Required parameter playlistId is missing")
+	songsToAdd := c.ParamStrings("songIdToAdd")
+	songIndexesToRemove := c.ParamInts("songIndexToRemove")
+
+	var pname *string
+	if len(c.Input()["name"]) > 0 {
+		s := c.Input()["name"][0]
+		pname = &s
+	}
+
+	beego.Info(fmt.Sprintf("Updating playlist with id '%s'", playlistId))
+	if pname != nil {
+		beego.Debug(fmt.Sprintf(" -- New Name: '%s'", *pname))
+	}
+	beego.Debug(fmt.Sprintf(" -- Adding: '%v'", songsToAdd))
+	beego.Debug(fmt.Sprintf(" -- Removing: '%v'", songIndexesToRemove))
+
+	err := c.pls.Update(playlistId, pname, songsToAdd, songIndexesToRemove)
+	if err != nil {
+		beego.Error(err)
+		c.SendError(responses.ErrorGeneric, "Internal Error")
+	}
+	c.SendEmptyResponse()
+}
+
 func (c *PlaylistsController) buildPlaylist(d *engine.PlaylistInfo) *responses.PlaylistWithSongs {
 	pls := &responses.PlaylistWithSongs{}
 	pls.Id = d.Id
diff --git a/conf/router.go b/conf/router.go
index 5afaa14a5..09eb17e86 100644
--- a/conf/router.go
+++ b/conf/router.go
@@ -42,6 +42,7 @@ func mapEndpoints() {
 		beego.NSRouter("/getPlaylists.view", &api.PlaylistsController{}, "*:GetAll"),
 		beego.NSRouter("/getPlaylist.view", &api.PlaylistsController{}, "*:Get"),
 		beego.NSRouter("/createPlaylist.view", &api.PlaylistsController{}, "*:Create"),
+		beego.NSRouter("/updatePlaylist.view", &api.PlaylistsController{}, "*:Update"),
 		beego.NSRouter("/deletePlaylist.view", &api.PlaylistsController{}, "*:Delete"),
 
 		beego.NSRouter("/getUser.view", &api.UsersController{}, "*:GetUser"),
diff --git a/domain/playlist.go b/domain/playlist.go
index c8ce1afa8..18b2cdf56 100644
--- a/domain/playlist.go
+++ b/domain/playlist.go
@@ -3,6 +3,7 @@ package domain
 type Playlist struct {
 	Id       string
 	Name     string
+	Comment  string
 	FullPath string
 	Duration int
 	Owner    string
diff --git a/engine/playlists.go b/engine/playlists.go
index 45c792e5e..9eb187e1a 100644
--- a/engine/playlists.go
+++ b/engine/playlists.go
@@ -2,6 +2,7 @@ package engine
 
 import (
 	"fmt"
+	"sort"
 
 	"github.com/astaxie/beego"
 	"github.com/deluan/gosonic/domain"
@@ -12,7 +13,8 @@ type Playlists interface {
 	GetAll() (domain.Playlists, error)
 	Get(id string) (*PlaylistInfo, error)
 	Create(name string, ids []string) error
-	Delete(id string) error
+	Delete(playlistId string) error
+	Update(playlistId string, name *string, idsToAdd []string, idxToRemove []int) error
 }
 
 func NewPlaylists(itunes itunesbridge.ItunesControl, pr domain.PlaylistRepository, mr domain.MediaFileRepository) Playlists {
@@ -37,6 +39,7 @@ type PlaylistInfo struct {
 	Duration  int
 	Public    bool
 	Owner     string
+	Comment   string
 }
 
 func (p *playlists) Create(name string, ids []string) error {
@@ -48,12 +51,39 @@ func (p *playlists) Create(name string, ids []string) error {
 	return nil
 }
 
-func (p *playlists) Delete(id string) error {
-	err := p.itunes.DeletePlaylist(id)
+func (p *playlists) Delete(playlistId string) error {
+	err := p.itunes.DeletePlaylist(playlistId)
 	if err != nil {
 		return err
 	}
-	beego.Info(fmt.Sprintf("Deleted playlist with id '%s'", id))
+	beego.Info(fmt.Sprintf("Deleted playlist with id '%s'", playlistId))
+	return nil
+}
+
+func (p *playlists) Update(playlistId string, name *string, idsToAdd []string, idxToRemove []int) error {
+	pl, err := p.plsRepo.Get(playlistId)
+	if err != nil {
+		return err
+	}
+	if name != nil {
+		pl.Name = *name
+		err := p.itunes.RenamePlaylist(pl.Id, pl.Name)
+		if err != nil {
+			return err
+		}
+	}
+	if len(idsToAdd) > 0 || len(idxToRemove) > 0 {
+		sort.Sort(sort.Reverse(sort.IntSlice(idxToRemove)))
+		for _, i := range idxToRemove {
+			pl.Tracks, pl.Tracks[len(pl.Tracks)-1] = append(pl.Tracks[:i], pl.Tracks[i+1:]...), ""
+		}
+		pl.Tracks = append(pl.Tracks, idsToAdd...)
+		err := p.itunes.UpdatePlaylist(pl.Id, pl.Tracks)
+		if err != nil {
+			return err
+		}
+	}
+	p.plsRepo.Put(pl)
 	return nil
 }
 
@@ -70,6 +100,7 @@ func (p *playlists) Get(id string) (*PlaylistInfo, error) {
 		Duration:  pl.Duration,
 		Public:    pl.Public,
 		Owner:     pl.Owner,
+		Comment:   pl.Comment,
 	}
 	pinfo.Entries = make(Entries, len(pl.Tracks))
 
diff --git a/itunesbridge/itunes.go b/itunesbridge/itunes.go
index 4b0ebe1b3..a2ec391b5 100644
--- a/itunesbridge/itunes.go
+++ b/itunesbridge/itunes.go
@@ -14,7 +14,9 @@ type ItunesControl interface {
 	SetTrackRating(trackId string, rating int) error
 	SetAlbumRating(trackId string, rating int) error
 	CreatePlaylist(name string, ids []string) (string, error)
-	DeletePlaylist(id string) error
+	UpdatePlaylist(playlistId string, ids []string) error
+	RenamePlaylist(playlistId, name string) error
+	DeletePlaylist(playlistId string) error
 }
 
 func NewItunesControl() ItunesControl {
@@ -40,9 +42,31 @@ func (c *itunesControl) CreatePlaylist(name string, ids []string) (string, error
 	return strings.TrimSuffix(pid, "\n"), nil
 }
 
-func (c *itunesControl) DeletePlaylist(id string) error {
+func (c *itunesControl) UpdatePlaylist(playlistId string, ids []string) error {
+	pids := `"` + strings.Join(ids, `","`) + `"`
 	script := Script{
-		fmt.Sprintf(`set pls to the first item of (every playlist whose persistent ID is equal to "%s")`, id),
+		fmt.Sprintf(`set pls to the first item of (every playlist whose persistent ID is equal to "%s")`, playlistId),
+		`delete every track of pls`,
+		fmt.Sprintf(`set pids to {%s}`, pids),
+		`repeat with trackPID in pids`,
+		`	set myTrack to the first item of (every track whose persistent ID is equal to trackPID)`,
+		`	duplicate myTrack to pls`,
+		`end repeat`}
+	return script.Run()
+}
+
+func (c *itunesControl) RenamePlaylist(playlistId, name string) error {
+	script := Script{
+		fmt.Sprintf(`set pls to the first item of (every playlist whose persistent ID is equal to "%s")`, playlistId),
+		`tell pls`,
+		fmt.Sprintf(`set name to "%s"`, name),
+		`end tell`}
+	return script.Run()
+}
+
+func (c *itunesControl) DeletePlaylist(playlistId string) error {
+	script := Script{
+		fmt.Sprintf(`set pls to the first item of (every playlist whose persistent ID is equal to "%s")`, playlistId),
 		`delete pls`,
 	}
 	return script.Run()
diff --git a/scanner/importer.go b/scanner/importer.go
index 56491cc9b..c8d18e4a0 100644
--- a/scanner/importer.go
+++ b/scanner/importer.go
@@ -217,6 +217,7 @@ func (i *Importer) importLibrary() (err error) {
 	for _, pl := range i.scanner.Playlists() {
 		pl.Public = true
 		pl.Owner = beego.AppConfig.String("user")
+		pl.Comment = "Original: " + pl.FullPath
 		pls[j] = *pl
 		j++
 		if err := i.plsRepo.Put(pl); err != nil {