package providers import ( "context" "net/url" "regexp" "sort" "strconv" "strings" ) // wikipedia finds stage works (musicals, plays, operas) on English // Wikipedia. There's no free, open theater database with an API, and // Wikipedia has the best coverage plus poster/logo art for most shows. The // specific production (Broadway, a tour, …) is chosen by the owner. type wikipedia struct { r *Registry // stage limits results to musicals, plays and operas. Custom lists // search all of Wikipedia. stage bool } func (w *wikipedia) Name() string { return "wikipedia" } func (w *wikipedia) Label() string { return "Wikipedia" } const theaterTemplates = `hastemplate:"Infobox musical|Infobox play|Infobox opera"` func (w *wikipedia) Search(ctx context.Context, query string) ([]Result, error) { if !w.stage { return w.search(ctx, query) } res, err := w.search(ctx, query+" "+theaterTemplates) if err == nil && len(res) == 0 { res, err = w.search(ctx, query) } return res, err } var leadingYear = regexp.MustCompile(`^(1[5-9]\d\d|20\d\d)\s+`) func (w *wikipedia) search(ctx context.Context, query string) ([]Result, error) { q := url.Values{ "action": {"query"}, "format": {"json"}, "formatversion": {"2"}, "generator": {"search"}, "gsrsearch": {query}, "gsrlimit": {"15"}, "prop": {"pageimages|description|info|extracts"}, "piprop": {"thumbnail"}, "pithumbsize": {"800"}, "pilicense": {"any"}, "inprop": {"url"}, "exintro": {"1"}, "explaintext": {"1"}, "exsentences": {"3"}, "exlimit": {"max"}, } var resp struct { Query struct { Pages []struct { PageID int64 `json:"pageid"` Title string `json:"title"` Index int `json:"index"` Description string `json:"description"` Extract string `json:"extract"` FullURL string `json:"fullurl"` Thumbnail struct { Source string `json:"source"` } `json:"thumbnail"` } `json:"pages"` } `json:"query"` } if err := w.r.getJSON(ctx, "https://en.wikipedia.org/w/api.php?"+q.Encode(), nil, &resp); err != nil { return nil, err } pages := resp.Query.Pages sort.Slice(pages, func(i, j int) bool { return pages[i].Index < pages[j].Index }) out := make([]Result, 0, len(pages)) for _, p := range pages { title := p.Title // "Hamilton (musical)" → "Hamilton" if i := strings.LastIndex(title, " ("); i > 0 && strings.HasSuffix(title, ")") { title = title[:i] } desc := leadingYear.ReplaceAllString(p.Description, "") if desc != "" { desc = strings.ToUpper(desc[:1]) + desc[1:] } img := p.Thumbnail.Source if i := strings.Index(img, "?"); i > 0 { img = img[:i] } out = append(out, Result{ Provider: "wikipedia", ProviderID: strconv.FormatInt(p.PageID, 10), Title: title, Subtitle: desc, Year: yearOf(p.Description), ImageURL: img, ExternalURL: p.FullURL, Overview: truncate(p.Extract, maxDescription), }) } return out, nil }