Files
pmomusic/internal/upnp/service.go
Eric Coissac 2a8bba25a1 Changes to be committed:
modified:   cmd/pmomusic/main.go
	modified:   go.mod
	modified:   go.sum
	modified:   internal/ssdp/responder.go
	modified:   internal/ssdp/ssdp.go
	new file:   internal/ssdp/uuid.go
	renamed:    internal/upnp/http.go -> internal/upnp/description_xml.go
	modified:   internal/upnp/device.go
	renamed:    web/index.html -> internal/upnp/html/index.html
	modified:   internal/upnp/server.go
	modified:   internal/upnp/service.go
	new file:   internal/upnp/xml/Info.xml
	new file:   internal/upnp/xml/Playlist.xml
	new file:   internal/upnp/xml/Product.xml
2025-06-08 21:39:58 +02:00

116 lines
2.4 KiB
Go

package upnp
import (
"bytes"
"fmt"
"strings"
"text/template"
)
type ServiceGroup string
const (
UPnP ServiceGroup = "upnp"
OpenHome ServiceGroup = "openhome"
Other ServiceGroup = "other"
)
type ServiceDescription struct {
Group ServiceGroup
Type string
Name string
ID string
URLPrefix string
XML string // auto-rempli temporairement pour le template parent
}
const serviceTemplate = `
<service>
<serviceType>{{.Type}}</serviceType>
<serviceId>{{.ID}}</serviceId>
<controlURL>{{.URLPrefix}}/control</controlURL>
<eventSubURL>{{.URLPrefix}}/event</eventSubURL>
<SCPDURL>{{.URLPrefix}}.xml</SCPDURL>
</service>
`
func NewServiceDescription(serviceType string) *ServiceDescription {
parts := strings.Split(serviceType, ":")
name := parts[len(parts)-2]
var group ServiceGroup
switch {
case strings.Contains(serviceType, "schemas-upnp-org"):
group = UPnP
case strings.Contains(serviceType, "av-openhome-org"):
group = OpenHome
default:
group = Other
}
id := fmt.Sprintf("urn:%s:serviceId:%s", string(group), name)
urlPrefix := fmt.Sprintf("/%s/%s", group, name)
return &ServiceDescription{
Group: group,
Type: serviceType,
Name: name,
ID: id,
URLPrefix: urlPrefix,
}
}
func (desc *ServiceDescription) GenerateServiceXML() (string, error) {
tmpl, err := template.New("service").Parse(strings.TrimSpace(serviceTemplate))
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, desc); err != nil {
return "", err
}
return buf.String(), nil
}
type ServiceList struct {
Services []*ServiceDescription
}
func NewServiceList() *ServiceList {
return &ServiceList{
Services: make([]*ServiceDescription, 0),
}
}
func (sl *ServiceList) Append(serviceType string) {
svc := NewServiceDescription(serviceType)
sl.Services = append(sl.Services, svc)
}
func (sl *ServiceList) GenerateServiceListXML() (string, error) {
const listTemplate = `
<serviceList>
{{range .Services}}{{.XML}}
{{end}}</serviceList>`
// Génère tous les XML individuellement
for _, svc := range sl.Services {
xml, err := svc.GenerateServiceXML()
if err != nil {
return "", err
}
svc.XML = xml
}
// Template principal
tmpl, err := template.New("list").Parse(strings.TrimSpace(listTemplate))
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, sl); err != nil {
return "", err
}
return buf.String(), nil
}