A scanned ATSC channel's number comes back as "14.1" rather than the packed integer, which stopped the antenna lineup from loading. Names lose the padding some stations send.
- commit
- 3febc87e2cc69b4c3bf7ca3bd1e3e33ca717aaa0
- parent
- 1b49589c385a1f85374e287f46985396a4fe37aa
- author
- FelineStateMachine <226808055+FelineStateMachine@users.noreply.github.com>
| M | internal/ | 26 | +++++++++++++++++++++++++ |
| M | internal/ | 31 | ++++++++++++++++++++++++------ |
@@ -5,6 +5,7 @@ import (
55 "encoding/json"66 "net/http"77 "net/http/httptest"8+ "strings"89 "testing"910 )1011 @@ -38,3 +39,28 @@ func TestFrontendsHDHomeRun(t *testing.T) {
3839 t.Fatalf("frontends: %+v", fes)3940 }4041 }42+43+// TestChannelsNumbers reads the channel grid as Tvheadend writes it: a44+// packed integer for a channel numbered by hand, a string for a scanned45+// ATSC channel, and names padded with spaces.46+func TestChannelsNumbers(t *testing.T) {47+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {48+ w.Write([]byte(`{"entries":[49+ {"uuid":"a","name":"Demo 7.1","number":7000001,"enabled":true},50+ {"uuid":"b","name":"Dabl ","number":"4.3","enabled":true,"services":["s"]},51+ {"uuid":"c","name":"KTVD","number":"20","enabled":false},52+ {"uuid":"d","name":"Unnumbered","enabled":true}]}`))53+ }))54+ defer srv.Close()55+ chans, err := New(srv.URL, srv.Client()).Channels(context.Background())56+ if err != nil {57+ t.Fatal(err)58+ }59+ var got []string60+ for _, c := range chans {61+ got = append(got, c.Number+" "+c.Name)62+ }63+ if want := []string{"7.1 Demo 7.1", "4.3 Dabl", "20 KTVD", "0 Unnumbered"}; strings.Join(got, "|") != strings.Join(want, "|") {64+ t.Errorf("channels: %q, want %q", got, want)65+ }66+}@@ -7,6 +7,7 @@ package tvh
77 88 import (99 "bytes"10+ "cmp"1011 "context"1112 "encoding/json"1213 "fmt"@@ -57,11 +58,11 @@ type Channel struct {
5758 func (c *Client) Channels(ctx context.Context) ([]Channel, error) {5859 var body struct {5960 Entries []struct {60- UUID string `json:"uuid"`61- Name string `json:"name"`62- Number int64 `json:"number"`63- Enabled bool `json:"enabled"`64- Services []string `json:"services"`61+ UUID string `json:"uuid"`62+ Name string `json:"name"`63+ Number gridNumber `json:"number"`64+ Enabled bool `json:"enabled"`65+ Services []string `json:"services"`6566 } `json:"entries"`6667 }6768 if err := c.get(ctx, "/api/channel/grid", url.Values{"limit": {"5000"}}, &body); err != nil {@@ -69,7 +70,7 @@ func (c *Client) Channels(ctx context.Context) ([]Channel, error) {
6970 }7071 out := make([]Channel, 0, len(body.Entries))7172 for _, e := range body.Entries {72- out = append(out, Channel{UUID: e.UUID, Name: e.Name, Number: FormatNumber(e.Number), Enabled: e.Enabled, Services: e.Services})73+ out = append(out, Channel{UUID: e.UUID, Name: strings.TrimSpace(e.Name), Number: cmp.Or(string(e.Number), "0"), Enabled: e.Enabled, Services: e.Services})7374 }7475 return out, nil7576 }@@ -100,6 +101,24 @@ func (c *Client) ServiceStreams(ctx context.Context, serviceUUID string) ([]Stre
100101 return out, nil101102 }102103 104+// gridNumber is a channel number as the channel grid writes it: a packed105+// integer (7000001), or for a real ATSC channel a string ("7.1").106+type gridNumber string107+108+func (n *gridNumber) UnmarshalJSON(raw []byte) error {109+ var s string110+ if err := json.Unmarshal(raw, &s); err == nil {111+ *n = gridNumber(strings.TrimSpace(s))112+ return nil113+ }114+ var packed int64115+ if err := json.Unmarshal(raw, &packed); err != nil {116+ return fmt.Errorf("channel number %s: %w", raw, err)117+ }118+ *n = gridNumber(FormatNumber(packed))119+ return nil120+}121+103122 // FormatNumber renders a packed channel number: 7000001 → "7.1", 27 → "27".104123 func FormatNumber(n int64) string {105124 major, minor := n/numberSplit, n%numberSplit