~hokiegeek/ytpulse

07b0d8e1bb4c2f7a581d31a1ce4c25f9898a8b3a — HokieGeek 2 months ago 2c784ac
Improves program support
4 files changed, 184 insertions(+), 225 deletions(-)

M program.go
M pulse.go
M serve.go
M session.go
M program.go => program.go +114 -112
@@ 1,7 1,6 @@
package ytpulse

import (
	"encoding/json"
	"fmt"

	"git.sr.ht/~hokiegeek/ytlibrarian"


@@ 15,6 14,7 @@ type Program struct {
	UserData userData `json:"userData,omitempty"`
}

/*
func (p Program) asYtlCollection() (ytlibrarian.Collection, error) {
	var ytl ytlibrarian.Collection
	ytl.ID = p.ID


@@ 50,16 50,45 @@ func ytlCollectionAsProgram(ytlc ytlibrarian.Collection) (Program, error) {
	}
	return p, err
}
*/

/*
type programCollection struct {
	pulseCollection
func (p Program) asPulseCollection() pulseCollection {
	var pc pulseCollection
	pc.ID = p.ID
	pc.ReferenceID = p.ReferenceID
	pc.Description = p.Description
	pc.Title = p.Title
	pc.ThumbnailURLs = p.ThumbnailURLs
	pc.DurationSecs = p.DurationSecs
	pc.PrivacyStatus = p.PrivacyStatus
	pc.Source = p.Source
	pc.URL = p.URL

	pc.Subtype = pulseCollectionProgram
	pc.UserData = p.UserData

	return pc
}

func (p pulseCollection) asProgram() Program {
	var g Program
	g.ID = p.ID
	g.ReferenceID = p.ReferenceID
	g.Description = p.Description
	g.Title = p.Title
	g.ThumbnailURLs = p.ThumbnailURLs
	g.DurationSecs = p.DurationSecs
	g.PrivacyStatus = p.PrivacyStatus
	g.Source = p.Source
	g.URL = p.URL
	g.UserData = p.UserData

	return g
}
*/

// ProgramDays collects the items within a Program
type ProgramDays struct {
	ProgramID string            `json:"program_id"`
	ProgramID string            `json:"programId"`
	Days      []ProgramDaysItem `json:"days,omitempty"`
	Data      string            `json:"data,omitempty"`
}


@@ 70,7 99,7 @@ func (c ProgramDays) byPosition(pos int) (ProgramDaysItem, error) {
			return item, nil
		}
	}
	return ProgramDaysItem{}, &ytlibrarian.ThingNotFoundError{Err: fmt.Errorf("did not find an ProgramDay at position %d", pos)}
	return ProgramDaysItem{}, &ytlibrarian.ThingNotFoundError{Err: fmt.Errorf("did not find a ProgramDay at position %d", pos)}
}

// ProgramDaysItem defines the minimum data to identify an item in a ProgramDay and its position in a Program


@@ 85,6 114,7 @@ type ProgramDay struct {
	UserData userData `json:"userData,omitempty"`
}

/*
func (p ProgramDay) asYtlCollection() (ytlibrarian.Collection, error) {
	var ytl ytlibrarian.Collection
	ytl.ID = p.ID


@@ 120,10 150,45 @@ func ytlCollectionAsProgramDay(ytlc ytlibrarian.Collection) (ProgramDay, error) 
	}
	return p, err
}
*/

func (p ProgramDay) asPulseCollection() pulseCollection {
	var pc pulseCollection
	pc.ID = p.ID
	pc.ReferenceID = p.ReferenceID
	pc.Description = p.Description
	pc.Title = p.Title
	pc.ThumbnailURLs = p.ThumbnailURLs
	pc.DurationSecs = p.DurationSecs
	pc.PrivacyStatus = p.PrivacyStatus
	pc.Source = p.Source
	pc.URL = p.URL

	pc.Subtype = pulseCollectionProgramDay
	pc.UserData = p.UserData

	return pc
}

func (p pulseCollection) asProgramDay() ProgramDay {
	var g ProgramDay
	g.ID = p.ID
	g.ReferenceID = p.ReferenceID
	g.Description = p.Description
	g.Title = p.Title
	g.ThumbnailURLs = p.ThumbnailURLs
	g.DurationSecs = p.DurationSecs
	g.PrivacyStatus = p.PrivacyStatus
	g.Source = p.Source
	g.URL = p.URL
	g.UserData = p.UserData

	return g
}

// ProgramDayItems collects the items within a ProgramDay
type ProgramDayItems struct {
	ProgramDayID string           `json:"program_day_id"`
	ProgramDayID string           `json:"programDayId"`
	Items        []ProgramDayItem `json:"items,omitempty"`
	Data         string           `json:"data,omitempty"`
}


@@ 144,42 209,20 @@ type ProgramDayItem struct {

// CreateProgram creates a new program in the thinger that is not associated with an external thing
func CreateProgram(librarian *ytlibrarian.Librarian, program Program, user User) (Program, error) {
	progCollection, err := program.asYtlCollection()
	if err != nil {
		return Program{}, fmt.Errorf("could not convert Program to Collection: %v", err)
	}

	ytluser := user.asYtlUser()
	ytlcollection, err := ytlibrarian.CreateCollection(librarian.Thinger, progCollection, ytluser)
	if err != nil {
		return Program{}, fmt.Errorf("librarian did not add Program: %v", err)
	}
	prog, err := ytlCollectionAsProgram(ytlcollection)
	pc, err := createPulseCollection(librarian, program.asPulseCollection(), user)
	if err != nil {
		return Program{}, fmt.Errorf("error processing Collection thing: %v", err)
		return Program{}, err
	}

	return prog, nil
	return pc.asProgram(), nil
}

// UpdateProgram updates an existing collection in the thinger
func UpdateProgram(librarian *ytlibrarian.Librarian, program Program, user User) (Program, error) {
	ytluser := user.asYtlUser()
	seshcollect, err := program.asYtlCollection()
	pc, err := updatePulseCollection(librarian, program.asPulseCollection(), user)
	if err != nil {
		return program, err
	}
	ytlcollection, err := ytlibrarian.UpdateCollection(librarian.Thinger, seshcollect, ytluser)
	if err != nil {
		return Program{}, fmt.Errorf("librarian did not update Program: %v", err)
	}

	sesh, err := ytlCollectionAsProgram(ytlcollection)
	if err != nil {
		return Program{}, fmt.Errorf("error processing Collection thing: %v", err)
		return Program{}, err
	}

	return sesh, nil
	return pc.asProgram(), nil
}

// AddProgram retrieves program details from a Tuber and adds a Program Thing to the given Thinger


@@ 205,75 248,56 @@ func AddProgram(librarian *ytlibrarian.Librarian, authToken string, user User, i

// GetProgramByID retrieves the program which matches the given ID
func GetProgramByID(librarian *ytlibrarian.Librarian, user User, id uuid.UUID) (Program, error) {
	ytluser := user.asYtlUser()
	ytlcollect, err := ytlibrarian.GetCollectionByID(librarian.Thinger, ytluser, id)
	if err != nil {
		return Program{}, err //fmt.Errorf("librarian failure retrieving Collection: %v", err)
	}
	sesh, err := ytlCollectionAsProgram(ytlcollect)
	pc, err := getPulseCollectionByID(librarian, user, id)
	if err != nil {
		return Program{}, err //fmt.Errorf("error processing librarian Collection: %v", err)
		return Program{}, err
	}
	return sesh, nil
	return pc.asProgram(), nil
}

// GetProgramByReferenceID retrieves the user thing by the given external ID
func GetProgramByReferenceID(librarian *ytlibrarian.Librarian, user User, refID string) (Program, error) {
	ytluser := user.asYtlUser()
	ytlcollection, err := ytlibrarian.GetCollectionByReferenceID(librarian.Thinger, ytluser, refID)
	pc, err := getPulseCollectionByReferenceID(librarian, user, refID)
	if err != nil {
		return Program{}, err
	}
	sesh, err := ytlCollectionAsProgram(ytlcollection)
	if err != nil {
		return Program{}, err // TODO
	}
	return sesh, nil
	return pc.asProgram(), nil
}

// GetProgramsByUser retrieves the sessions which belong to the given user
func GetProgramsByUser(librarian *ytlibrarian.Librarian, user User) ([]Program, error) {
	ytluser := user.asYtlUser()
	ytlcollections, err := ytlibrarian.GetCollectionsByUser(librarian.Thinger, ytluser)
	pcs, err := getPulseCollectionsByUser(librarian, user)
	if err != nil {
		return nil, err
	}

	var bulkErr ytlibrarian.BulkItemError
	sessions := make([]Program, len(ytlcollections))
	for i, ytc := range ytlcollections {
		sessions[i], err = ytlCollectionAsProgram(ytc)
		if err != nil {
			bulkErr.IDs = append(bulkErr.IDs, ytc.ID.String())
			bulkErr.Errors = append(bulkErr.Errors, err)
			continue
	programs := make([]Program, 0)
	for _, pc := range pcs {
		if pc.Subtype == pulseCollectionProgram {
			programs = append(programs, pc.asProgram())
			if err != nil {
				bulkErr.IDs = append(bulkErr.IDs, pc.ID.String())
				bulkErr.Errors = append(bulkErr.Errors, err)
				continue
			}
		}
	}
	if len(bulkErr.Errors) > 0 {
		return nil, &bulkErr
	}

	return sessions, nil
	return programs, nil
}

// LinkProgramToUser adds a relationship between a user and a given program as well as the items
func LinkProgramToUser(librarian *ytlibrarian.Librarian, program Program, user User, details string) error {
	ytlcollection, err := program.asYtlCollection()
	if err != nil {
		return err
	}
	ytluser := user.asYtlUser()
	return ytlibrarian.LinkCollectionToUser(librarian.Thinger, ytlcollection, ytluser, details)
	return linkPulseCollectionToUser(librarian, program.asPulseCollection(), user, details)
}

// UnlinkProgramAndUser removes relationship between a program and a user
func UnlinkProgramAndUser(librarian *ytlibrarian.Librarian, program Program, user User) error {
	ytlcollection, err := program.asYtlCollection()
	if err != nil {
		return err
	}
	ytluser := user.asYtlUser()
	return ytlibrarian.UnlinkCollectionAndUser(librarian.Thinger, ytlcollection, ytluser)
	return unlinkPulseCollectionAndUser(librarian, program.asPulseCollection(), user)
}

// RemoveProgramByID removes the identified program from the Thinger


@@ 283,32 307,17 @@ func RemoveProgramByID(librarian *ytlibrarian.Librarian, id uuid.UUID) error {

// UpdateProgramCustomData links the given data to a Program on behalf of a User
func UpdateProgramCustomData(librarian *ytlibrarian.Librarian, program Program, user User) error {
	ytlcollection, err := program.asYtlCollection()
	if err != nil {
		return err
	}
	ytluser := user.asYtlUser()
	return ytlibrarian.UpdateCollectionCustomData(librarian.Thinger, ytlcollection, ytluser, ytlcollection.Data)
	return updatePulseCollectionCustomData(librarian, program.asPulseCollection(), user)
}

// GetUserProgramCustomData retrieves the given data to a Program on behalf of a User
func GetUserProgramCustomData(librarian *ytlibrarian.Librarian, program Program, user User) (string, error) {
	ytlcollection, err := program.asYtlCollection()
	if err != nil {
		return "", err
	}
	ytluser := user.asYtlUser()
	return ytlibrarian.GetUserCollectionCustomData(librarian.Thinger, ytlcollection, ytluser)
	return getUserPulseCollectionCustomData(librarian, program.asPulseCollection(), user)
}

// RemoveUserProgramCustomData does what it says on the tin
func RemoveUserProgramCustomData(librarian *ytlibrarian.Librarian, program Program, user User) error {
	ytlcollection, err := program.asYtlCollection()
	if err != nil {
		return err
	}
	ytluser := user.asYtlUser()
	return ytlibrarian.RemoveUserCollectionCustomData(librarian.Thinger, ytlcollection, ytluser)
	return removeUserPulseCollectionCustomData(librarian, program.asPulseCollection(), user)
}

// GetProgramDays retrieves the program days which matches the given ID


@@ 352,18 361,22 @@ func UpdateProgramDays(librarian *ytlibrarian.Librarian, user User, days Program
	return ytlibrarian.UpdateCollectionItems(librarian.Thinger, ytluser, citems)
}

// GetProgramDayByID retrieves the program which matches the given ID
func GetProgramDayByID(librarian *ytlibrarian.Librarian, user User, id uuid.UUID) (ProgramDay, error) {
	ytluser := user.asYtlUser()
	ytlcollect, err := ytlibrarian.GetCollectionByID(librarian.Thinger, ytluser, id)
// CreateProgramDay creates a new program day in the thinger that is not associated with an external thing
func CreateProgramDay(librarian *ytlibrarian.Librarian, programDay ProgramDay, user User) (ProgramDay, error) {
	pc, err := createPulseCollection(librarian, programDay.asPulseCollection(), user)
	if err != nil {
		return ProgramDay{}, err //fmt.Errorf("librarian failure retrieving Collection: %v", err)
		return ProgramDay{}, err
	}
	day, err := ytlCollectionAsProgramDay(ytlcollect)
	return pc.asProgramDay(), nil
}

// GetProgramDayByID retrieves the program which matches the given ID
func GetProgramDayByID(librarian *ytlibrarian.Librarian, user User, id uuid.UUID) (ProgramDay, error) {
	pc, err := getPulseCollectionByID(librarian, user, id)
	if err != nil {
		return ProgramDay{}, err //fmt.Errorf("error processing librarian Collection: %v", err)
		return ProgramDay{}, err
	}
	return day, nil
	return pc.asProgramDay(), nil
}

// InsertProgramDay adds a day to a Program


@@ 456,23 469,12 @@ func AppendProgramDayItem(librarian *ytlibrarian.Librarian, user User, programDa

// PublishProgramDay inserts or updates the identified program day to the given tuber service
func PublishProgramDay(librarian *ytlibrarian.Librarian, user User, authToken string, id uuid.UUID) (ProgramDay, error) {
	tuber, err := librarian.CreateTuber(&oauth2.Token{RefreshToken: authToken})
	if err != nil {
		return ProgramDay{}, fmt.Errorf("error instantiating Tuber: %v", err)
	}

	ytluser := user.asYtlUser()
	collection, err := ytlibrarian.PublishCollection(librarian.Thinger, tuber, ytluser, id)
	if err != nil {
		return ProgramDay{}, err
	}

	day, err := ytlCollectionAsProgramDay(collection)
	pc, err := publishPulseCollection(librarian, user, authToken, id)
	if err != nil {
		return ProgramDay{}, err
	}

	return day, nil
	return pc.asProgramDay(), nil
}

// UnpublishProgramDay inserts or updates the identified program day to the given tuber service

M pulse.go => pulse.go +0 -10
@@ 3,7 3,6 @@ package ytpulse
import (
	"encoding/json"
	"fmt"
	"log"

	"git.sr.ht/~hokiegeek/ytlibrarian"
	"github.com/google/uuid"


@@ 51,16 50,12 @@ func (p pulseCollection) asYtlCollection() (ytlibrarian.Collection, error) {

func ytlCollectionAsPulseCollection(ytlc ytlibrarian.Collection) (pulseCollection, error) {
	var p pulseCollection
	log.Println("afp: >>>>> ytlCollectionAsPulseCollection: ytlc", ytlc)
	log.Println("afp: >>>>> ytlCollectionAsPulseCollection: ytlc.Data", ytlc.Data)

	var err error
	if ytlc.Data != "" {
		err = json.Unmarshal([]byte(ytlc.Data), &p)
	}

	log.Println("afp: >>>>> ytlCollectionAsPulseCollection: p.Subtype", p.Subtype)

	p.ID = ytlc.ID
	p.ReferenceID = ytlc.ReferenceID
	p.Description = ytlc.Description


@@ 75,25 70,20 @@ func ytlCollectionAsPulseCollection(ytlc ytlibrarian.Collection) (pulseCollectio
}

func createPulseCollection(librarian *ytlibrarian.Librarian, pulseColl pulseCollection, user User) (pulseCollection, error) {
	log.Println("afp: createPC: pulseColl ", pulseColl)
	pcAsColl, err := pulseColl.asYtlCollection()
	if err != nil {
		return pulseCollection{}, fmt.Errorf("could not convert pulse collection to Collection: %v", err)
	}
	log.Println("afp: createPC: pcAsColl ", pcAsColl)
	log.Println("afp: createPC: pcAsColl.Data ", pcAsColl.Data)

	ytluser := user.asYtlUser()
	ytlcollection, err := ytlibrarian.CreateCollection(librarian.Thinger, pcAsColl, ytluser)
	if err != nil {
		return pulseCollection{}, fmt.Errorf("librarian did not add pulse collection: %v", err)
	}
	log.Println("afp: createPC: ytlc ", ytlcollection)
	pc, err := ytlCollectionAsPulseCollection(ytlcollection)
	if err != nil {
		return pulseCollection{}, fmt.Errorf("error processing Collection thing: %v", err)
	}
	log.Println("afp: createPC(done): pc ", pc)

	return pc, nil
}

M serve.go => serve.go +70 -5
@@ 104,7 104,7 @@ func ListenAndServe(port string) error {
	router.PUT("/programs/:id/days", updateProgramDays)

	router.GET("/programs/:id/days/:day", getProgramDay)
	router.POST("/programs/:id/days/:day", insertProgramDay)
	// router.POST("/programs/:id/days/:day", insertProgramDay)
	router.PUT("/programs/:id/days/:day", updateProgramDay)
	router.DELETE("/programs/:id/days/:day", removeDayFromProgram)



@@ 257,7 257,6 @@ func authorizeUser(c *gin.Context) {
		if oauthCode == "" {
			c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		} else {
			log.Printf("afp: wtf: %v\n", err)
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
		}
		return


@@ 1956,6 1955,29 @@ func getProgramDayItemByPos(c *gin.Context, librarian *ytlibrarian.Librarian) (P
	return items.byPosition(itemPosition)
}

func insertEmptyProgramDay(c *gin.Context, librarian *ytlibrarian.Librarian, user User) (ProgramDay, error) {
	programID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		return ProgramDay{}, err
	}

	dayPos, err := strconv.Atoi(c.Param("day"))
	if err != nil {
		return ProgramDay{}, err
	}

	programDay, err := CreateProgramDay(librarian, ProgramDay{}, user)
	if err != nil {
		return ProgramDay{}, err
	}

	if err := InsertProgramDay(librarian, user, programID, programDay.ID, dayPos); err != nil {
		return ProgramDay{}, err
	}

	return programDay, nil
}

// GET /programs/:id/days/:day/items/:pos
func getProgramDayItem(c *gin.Context) {
	librarian, err := ytlibrarian.New()


@@ 2023,18 2045,61 @@ func insertProgramDayItem(c *gin.Context) {
		return
	}

	programDay, err := getProgramDaysItemByPos(c, librarian)
	var programDayID uuid.UUID
	programDayItem, err := getProgramDaysItemByPos(c, librarian)
	if err != nil {
		var nterr *ytlibrarian.ThingNotFoundError
		if errors.As(err, &nterr) {
			c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
			// c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
			/*
				programID, err := uuid.Parse(c.Param("id"))
				if err != nil {
					c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
					return
				}

				dayPos, err := strconv.Atoi(c.Param("day"))
				if err != nil {
					c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
					return
				}
			*/

			programDay, err := insertEmptyProgramDay(c, librarian, user)
			if err != nil {
				var nterr *ytlibrarian.ThingNotFoundError
				if errors.As(err, &nterr) {
					c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
				} else {
					c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
				}
			}
			programDayID = programDay.ID

			/*
				programDay, err := CreateProgramDay(librarian, ProgramDay{}, user)
				if err != nil {
					c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
					return
				}

				if err := InsertProgramDay(librarian, user, programID, programDay.ID, dayPos); err != nil {
					var nterr *ytlibrarian.ThingNotFoundError
					if errors.As(err, &nterr) {
						c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
					} else {
						c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
					}
					// return
				}
			*/
		} else {
			c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
		return
	}

	programDayID, err := uuid.Parse(programDay.ID)
	programDayID, err = uuid.Parse(programDayItem.ID)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return

M session.go => session.go +0 -98
@@ 1,9 1,7 @@
package ytpulse

import (
	"encoding/json"
	"fmt"
	"log"

	"git.sr.ht/~hokiegeek/ytlibrarian"
	"github.com/google/uuid"


@@ 34,42 32,6 @@ func (s Session) asPulseCollection() pulseCollection {
	return pc
}

func (s Session) asYtlCollection() (ytlibrarian.Collection, error) {
	var ytl ytlibrarian.Collection
	ytl.ID = s.ID
	ytl.ReferenceID = s.ReferenceID
	ytl.Description = s.Description
	ytl.Title = s.Title
	ytl.ThumbnailURLs = s.ThumbnailURLs
	ytl.DurationSecs = s.DurationSecs
	ytl.PrivacyStatus = s.PrivacyStatus
	ytl.Source = s.Source
	ytl.URL = s.URL

	deets, err := json.Marshal(&s.UserData)
	ytl.Data = string(deets)
	return ytl, err
}

func ytlCollectionAsSession(ytlc ytlibrarian.Collection) (Session, error) {
	var s Session
	s.ID = ytlc.ID
	s.ReferenceID = ytlc.ReferenceID
	s.Description = ytlc.Description
	s.Title = ytlc.Title
	s.ThumbnailURLs = ytlc.ThumbnailURLs
	s.DurationSecs = ytlc.DurationSecs
	s.PrivacyStatus = ytlc.PrivacyStatus
	s.Source = ytlc.Source
	s.URL = ytlc.URL

	var err error
	if ytlc.Data != "" {
		err = json.Unmarshal([]byte(ytlc.Data), &s.UserData)
	}
	return s, err
}

func (p pulseCollection) asSession() Session {
	var s Session
	s.ID = p.ID


@@ 84,14 46,6 @@ func (p pulseCollection) asSession() Session {
	s.UserData = p.UserData

	return s

	/*
		var err error
		if p.Data != "" {
			err = json.Unmarshal([]byte(p.UserData), &s.UserData)
		}
		return s, err
	*/
}

// SessionItems collects the items within a collection


@@ 170,8 124,6 @@ func GetSessionsByUser(librarian *ytlibrarian.Librarian, user User) ([]Session, 
	var bulkErr ytlibrarian.BulkItemError
	sessions := make([]Session, 0)
	for _, pc := range pcs {
		log.Println("afp: got pc:", pc)
		log.Println("afp: got pc subtype:", pc.Subtype)
		if pc.Subtype == pulseCollectionSession {
			sessions = append(sessions, pc.asSession())
			if err != nil {


@@ 206,47 158,16 @@ func RemoveSessionByID(librarian *ytlibrarian.Librarian, id uuid.UUID) error {
// UpdateSessionCustomData links the given data to a Session on behalf of a User
func UpdateSessionCustomData(librarian *ytlibrarian.Librarian, session Session, user User) error {
	return updatePulseCollectionCustomData(librarian, session.asPulseCollection(), user)
	/*
		pc, err := getPulseCollectionByReferenceID(librarian, user, refID)
		if err != nil {
			return Session{}, err
		}
		return pc.asSession(), nil
	*/
	/*
		ytlcollection, err := session.asYtlCollection()
		if err != nil {
			return err
		}
		ytluser := user.asYtlUser()
		return ytlibrarian.UpdateCollectionCustomData(librarian.Thinger, ytlcollection, ytluser, ytlcollection.Data)
	*/
}

// GetUserSessionCustomData retrieves the given data to a Session on behalf of a User
func GetUserSessionCustomData(librarian *ytlibrarian.Librarian, session Session, user User) (string, error) {
	return getUserPulseCollectionCustomData(librarian, session.asPulseCollection(), user)
	/*
		ytlcollection, err := session.asYtlCollection()
		if err != nil {
			return "", err
		}
		ytluser := user.asYtlUser()
		return ytlibrarian.GetUserCollectionCustomData(librarian.Thinger, ytlcollection, ytluser)
	*/
}

// RemoveUserSessionCustomData does what it says on the tin
func RemoveUserSessionCustomData(librarian *ytlibrarian.Librarian, session Session, user User) error {
	return removeUserPulseCollectionCustomData(librarian, session.asPulseCollection(), user)
	/*
		ytlcollection, err := session.asYtlCollection()
		if err != nil {
			return err
		}
		ytluser := user.asYtlUser()
		return ytlibrarian.RemoveUserCollectionCustomData(librarian.Thinger, ytlcollection, ytluser)
	*/
}

// GetSessionItems retrieves the session which matches the given ID


@@ 321,25 242,6 @@ func PublishSession(librarian *ytlibrarian.Librarian, user User, authToken strin
	}

	return pc.asSession(), nil
	/*
		tuber, err := librarian.CreateTuber(&oauth2.Token{RefreshToken: authToken})
		if err != nil {
			return Session{}, fmt.Errorf("error instantiating Tuber: %v", err)
		}

		ytluser := user.asYtlUser()
		collection, err := ytlibrarian.PublishCollection(librarian.Thinger, tuber, ytluser, id)
		if err != nil {
			return Session{}, err
		}

		session, err := ytlCollectionAsSession(collection)
		if err != nil {
			return Session{}, err
		}

		return session, nil
	*/
}

// UnpublishSession inserts or updates the identified session to the given tuber service