/
library.go
124 lines (104 loc) · 3.27 KB
/
library.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"net/http"
"path/filepath"
"strings"
"golang.org/x/net/context"
"tchaik.com/index"
"tchaik.com/index/attr"
"tchaik.com/store"
)
// Library is a type which encompases the components which form a full library.
type Library struct {
index.Library
collections map[string]index.Collection
filters map[string]index.Filter
recent Lister
searcher index.Searcher
}
func NewLibrary(l index.Library) Library {
fmt.Printf("Building root collection...")
root := buildRootCollection(l)
fmt.Println("done.")
fmt.Printf("Processing artist names and composers...")
rootSplit := index.SubTransform(root, index.SplitList("Artist", "Composer"))
fmt.Println("done.")
return Library{
Library: l,
collections: map[string]index.Collection{
"Root": root,
},
filters: map[string]index.Filter{
"Artist": newBootstrapFilter(rootSplit, attr.Strings("Artist")),
"Composer": newBootstrapFilter(rootSplit, attr.Strings("Composer")),
},
recent: &bootstrapRecent{root: root, n: 150},
searcher: newBootstrapSearcher(root),
}
}
type libraryFileSystem struct {
store.FileSystem
index.Library
}
// Open implements store.FileSystem and rewrites ID values to their corresponding Location
// values using the index.Library.
func (l *libraryFileSystem) Open(ctx context.Context, path string) (http.File, error) {
t, ok := l.Library.Track(strings.Trim(path, "/")) // IDs arrive with leading slash
if !ok {
return nil, fmt.Errorf("could not find track: %v", path)
}
loc := t.GetString("Location")
if loc == "" {
return nil, fmt.Errorf("invalid (empty) location for track: %v", path)
}
loc = filepath.ToSlash(loc)
return l.FileSystem.Open(ctx, loc)
}
// Fetch fetches a Group and its corresponding Key given a path. Returns an error if the path
// is invalid.
func (l *Library) Fetch(p index.Path) (index.Group, index.Key, error) {
if len(p) == 0 {
return nil, "", fmt.Errorf("invalid path: %v\n", p)
}
root := l.collections[string(p[0])]
if root == nil {
return nil, "", fmt.Errorf("unknown collection: %#v", p[0])
}
if len(p) == 1 {
return root, p[0], nil
}
g, err := l.Build(root, p[1:])
if err != nil {
return nil, "", fmt.Errorf("error in Fetch: %v (path: %#v)", err, p[1:])
}
return g, p[1], nil
}
// Build fetches a Group from the index.Collection given by the Path.
func (l *Library) Build(c index.Collection, p index.Path) (index.Group, error) {
if len(p) == 0 {
return c, nil
}
g, err := index.GroupFromPath(&rootCollection{c}, p)
if err != nil {
return nil, err
}
g = index.FirstTrackAttr(attr.String("ID"), g)
return g, nil
}
// FileSystem wraps the http.FileSystem in a library lookup which will translate /ID
// requests into their corresponding track paths.
func (l *Library) FileSystem(fs store.FileSystem) store.FileSystem {
return store.Trace(&libraryFileSystem{fs, l.Library}, "libraryFileSystem")
}
// ExpandPaths constructs a collection (group) whose sub-groups are taken from the "Root"
// collection.
func (l *Library) ExpandPaths(paths []index.Path) index.Group {
return &Group{
Group: index.NewPathsCollection(l.collections["Root"], paths),
Key: index.Key("Root"),
}
}