Phase 3: OpenSubsonic core (response envelope, error codes 42-44, getOpenSubsonicExtensions) and apiKeyAuthentication extension with tokenInfo, web API key management

This commit is contained in:
2026-08-23 08:04:01 -05:00
parent 3b4883780b
commit e38d31d384
17 changed files with 763 additions and 37 deletions
+125
View File
@@ -0,0 +1,125 @@
package subsonic
// --- songLyrics extension (versions 1 and 2) ---
type LyricsList struct {
StructuredLyrics []StructuredLyrics `xml:"structuredLyrics,omitempty" json:"structuredLyrics,omitempty"`
}
type StructuredLyrics struct {
Lang string `xml:"lang,attr" json:"lang"`
Synced bool `xml:"synced,attr" json:"synced"`
DisplayArtist string `xml:"displayArtist,attr,omitempty" json:"displayArtist,omitempty"`
DisplayTitle string `xml:"displayTitle,attr,omitempty" json:"displayTitle,omitempty"`
Offset int `xml:"offset,attr,omitempty" json:"offset,omitempty"`
Kind string `xml:"kind,attr,omitempty" json:"kind,omitempty"` // main|translation|pronunciation; v2 only
Line []Line `xml:"line" json:"line"`
Agents []Agent `xml:"agent,omitempty" json:"agents,omitempty"` // v2 only
CueLine []CueLine `xml:"cueLine,omitempty" json:"cueLine,omitempty"` // v2 only, synced entries only
}
type Line struct {
Value string `xml:",chardata" json:"value"`
Start *int `xml:"start,attr,omitempty" json:"start,omitempty"`
}
type Agent struct {
ID string `xml:"id,attr" json:"id"`
Role string `xml:"role,attr" json:"role"` // main|voice|bg|group
Name string `xml:"name,attr,omitempty" json:"name,omitempty"`
}
type CueLine struct {
Index int `xml:"index,attr" json:"index"`
Start int `xml:"start,attr,omitempty" json:"start,omitempty"`
End int `xml:"end,attr,omitempty" json:"end,omitempty"`
Value string `xml:"value,attr" json:"value"`
AgentID string `xml:"agentId,attr,omitempty" json:"agentId,omitempty"`
Cue []Cue `xml:"cue" json:"cue"`
}
type Cue struct {
Start int `xml:"start,attr" json:"start"`
End *int `xml:"end,attr,omitempty" json:"end,omitempty"`
ByteStart int `xml:"byteStart,attr" json:"byteStart"`
ByteEnd int `xml:"byteEnd,attr" json:"byteEnd"`
Value string `xml:"value,attr,omitempty" json:"value,omitempty"`
}
// --- sonicSimilarity extension ---
type SonicMatch struct {
Entry Child `xml:"entry" json:"entry"`
Similarity float64 `xml:"similarity,attr" json:"similarity"`
}
// --- transcoding extension ---
type ClientInfo struct {
Name string `json:"name"`
Platform string `json:"platform"`
MaxAudioBitrate int `json:"maxAudioBitrate,omitempty"`
MaxTranscodingAudioBitrate int `json:"maxTranscodingAudioBitrate,omitempty"`
DirectPlayProfiles []DirectPlayProfile `json:"directPlayProfiles,omitempty"`
TranscodingProfiles []TranscodingProfile `json:"transcodingProfiles,omitempty"`
CodecProfiles []CodecProfile `json:"codecProfiles,omitempty"`
}
type DirectPlayProfile struct {
Containers []string `json:"containers"`
AudioCodecs []string `json:"audioCodecs"`
Protocols []string `json:"protocols"`
MaxAudioChannels int `json:"maxAudioChannels,omitempty"`
}
type TranscodingProfile struct {
Container string `json:"container"`
AudioCodec string `json:"audioCodec"`
Protocol string `json:"protocol"`
MaxAudioChannels int `json:"maxAudioChannels,omitempty"`
}
type CodecProfile struct {
Type string `json:"type"`
Name string `json:"name"`
Limitations []Limitation `json:"limitations,omitempty"`
}
type Limitation struct {
Name string `json:"name"` // audioChannels|audioBitrate|audioProfile|audioSamplerate|audioBitdepth
Comparison string `json:"comparison"` // Equals|NotEquals|LessThanEqual|GreaterThanEqual
Values []string `json:"values"`
Required bool `json:"required"`
}
type StreamDetails struct {
Protocol string `xml:"protocol,attr" json:"protocol"`
Container string `xml:"container,attr" json:"container"`
Codec string `xml:"codec,attr" json:"codec"`
AudioChannels int `xml:"audioChannels,attr,omitempty" json:"audioChannels,omitempty"`
AudioBitrate int `xml:"audioBitrate,attr,omitempty" json:"audioBitrate,omitempty"`
AudioProfile string `xml:"audioProfile,attr,omitempty" json:"audioProfile,omitempty"`
AudioSamplerate int `xml:"audioSamplerate,attr,omitempty" json:"audioSamplerate,omitempty"`
AudioBitdepth int `xml:"audioBitdepth,attr,omitempty" json:"audioBitdepth,omitempty"`
}
type TranscodeDecision struct {
CanDirectPlay bool `xml:"canDirectPlay,attr" json:"canDirectPlay"`
CanTranscode bool `xml:"canTranscode,attr" json:"canTranscode"`
TranscodeReason []string `xml:"transcodeReason,omitempty" json:"transcodeReason,omitempty"`
ErrorReason string `xml:"errorReason,attr,omitempty" json:"errorReason,omitempty"`
TranscodeParams string `xml:"transcodeParams,attr,omitempty" json:"transcodeParams,omitempty"`
SourceStream *StreamDetails `xml:"sourceStream,omitempty" json:"sourceStream,omitempty"`
TranscodeStream *StreamDetails `xml:"transcodeStream,omitempty" json:"transcodeStream,omitempty"`
}
// --- index-based queue extension ---
type PlayQueueByIndex struct {
CurrentIndex int `xml:"currentIndex,attr" json:"currentIndex"`
Position int64 `xml:"position,attr,omitempty" json:"position,omitempty"`
Username string `xml:"username,attr" json:"username"`
Changed string `xml:"changed,attr" json:"changed"`
ChangedBy string `xml:"changedBy,attr" json:"changedBy"`
Entry []Child `xml:"entry,omitempty" json:"entry,omitempty"`
}