123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- package wikidata
- import (
- "notabug.org/apiote/amuse/datastructure"
- "notabug.org/apiote/amuse/network"
- "database/sql"
- "encoding/json"
- "net/http"
- "sort"
- "strings"
- "notabug.org/apiote/gott"
- )
- type Ordinals struct {
- Entities map[string]struct {
- Claims struct {
- P527 []struct {
- Mainsnak struct {
- Datavalue struct {
- Value struct {
- Id string
- }
- }
- }
- Qualifiers struct {
- P1545 []struct {
- Datavalue struct {
- Value string
- }
- }
- }
- }
- }
- }
- }
- type BookSeriePart struct {
- Cover string
- Ordinal string
- Title string
- Uri string
- }
- type BookSerie struct {
- Title string
- Cover string // note maybe first book’s cover?
- Description string
- Authors []string
- Genres []string
- Source []datastructure.Source
- Article string
- Parts map[string]BookSeriePart
- SortedParts []BookSeriePart
- }
- func (s BookSerie) GetArticle() string {
- return s.Article
- }
- func (s *BookSerie) SetDescription(description string) {
- s.Description = description
- }
- func queryBookSerie(args ...interface{}) (interface{}, error) {
- id := args[0].(*network.Request).Id
- tag := args[0].(*network.Request).Language[:2]
- result := args[1].(*Result)
- repo := result.Repo
- res, err := repo.Query(`SELECT ?title ?seriesLabel ?genreLabel ?authorLabel ?partLabel ?partTitle ?part ?article_title WHERE {
- ` + id + ` wdt:P50 ?author;
- wdt:P1476 ?title;
- wdt:P527 ?part.
- ?part wdt:P1476 ?partTitle.
- OPTIONAL {
- ` + id + ` wdt:P136 ?genre.
- }
- OPTIONAL {
- ?article schema:about ` + id + `;
- schema:inLanguage "` + tag + `";
- schema:name ?article_title;
- schema:isPartOf _:b18.
- _:b18 wikibase:wikiGroup "wikipedia".
- FILTER(!(CONTAINS(?article_title, ":")))
- }
- SERVICE wikibase:label { bd:serviceParam wikibase:language "` + tag + `", "en". }
- SERVICE wikibase:label {
- bd:serviceParam wikibase:language "` + tag + `", "en".
- ` + id + ` rdfs:label ?seriesLabel.
- }
- }`)
- result.Result = res
- return gott.Tuple(args), err
- }
- func parseBookSerie(args ...interface{}) interface{} {
- id := args[0].(*network.Request).Id
- results := args[1].(*Result)
- res := results.Result
- if res.Results.Bindings == nil || len(res.Results.Bindings) == 0 {
- results.Work = &BookSerie{}
- } else {
- authors := map[string]bool{}
- genres := map[string]bool{}
- result := res.Results.Bindings[0]
- title := result["bookLabel"].Value
- if title == strings.Replace(id, "wd:", "", 1) || title == "" {
- title = result["title"].Value
- }
- bookSerie := BookSerie{
- Title: title,
- Source: []datastructure.Source{},
- Authors: []string{},
- Genres: []string{},
- Article: result["article_title"].Value,
- Parts: map[string]BookSeriePart{},
- }
- for _, r := range res.Results.Bindings {
- authors[r["authorLabel"].Value] = true
- if r["genreLabel"].Value != "" {
- genres[r["genreLabel"].Value] = true
- }
- title := r["partLabel"].Value
- if title == strings.Replace(r["part"].Value, "http://www.wikidata.org/entity/", "", 1) || title == "" {
- title = r["partTitle"].Value
- }
- partId := strings.Replace(r["part"].Value, "http://www.wikidata.org/entity/", "", 1)
- bookSerie.Parts[partId] = BookSeriePart{
- Uri: strings.Replace(r["part"].Value, "http://www.wikidata.org/entity/", "/books/wd:", 1),
- Title: title,
- }
- }
- bookSerie.Source = append(bookSerie.Source, datastructure.Source{
- Url: "https://www.wikidata.org/wiki/" + strings.Replace(id, "wd:", "", 1),
- Name: "Wikidata",
- })
- bookSerie.Source = append(bookSerie.Source, datastructure.Source{
- Url: "https://inventaire.io/entity/" + id,
- Name: "Inventaire",
- })
- for k := range authors {
- bookSerie.Authors = append(bookSerie.Authors, k)
- }
- for k := range genres {
- bookSerie.Genres = append(bookSerie.Genres, k)
- }
- results.Work = &bookSerie
- }
- return gott.Tuple(args)
- }
- func createOrdinalsRequest(args ...interface{}) (interface{}, error) {
- request := args[0].(*network.Request)
- result := args[1].(*network.Result)
- id := strings.Replace(request.Id, "wd:", "", 1)
- client := &http.Client{}
- httpRequest, err := http.NewRequest("GET", "https://www.wikidata.org/wiki/Special:EntityData/"+id+".json", nil)
- result.Client = client
- result.Request = httpRequest
- return gott.Tuple(args), err
- }
- func unmarshalOrdinals(args ...interface{}) (interface{}, error) {
- result := args[1].(*network.Result)
- var ordinals Ordinals
- err := json.Unmarshal(result.Body, &ordinals)
- result.Result = ordinals
- return gott.Tuple(args), err
- }
- func sortOrdinals(args ...interface{}) (interface{}, error) {
- bookSerie := args[2].(*BookSerie)
- ordinals := args[1].(*network.Result).Result.(Ordinals).Entities
- sorted := []BookSeriePart{}
- for _, entity := range ordinals {
- for _, claim := range entity.Claims.P527 {
- id := claim.Mainsnak.Datavalue.Value.Id
- part := bookSerie.Parts[id]
- if len(claim.Qualifiers.P1545) > 0 {
- ordinal := claim.Qualifiers.P1545[0].Datavalue.Value
- part.Ordinal = ordinal
- } else {
- part.Ordinal = ""
- }
- sorted = append(sorted, part)
- }
- }
- sort.Slice(sorted, func(i, j int) bool {
- if sorted[i].Ordinal == "prologue" || sorted[j].Ordinal == "epilogue" {
- return true
- } else if sorted[i].Ordinal == "epilogue" || sorted[j].Ordinal == "prologue" {
- return false
- } else {
- return sorted[i].Ordinal < sorted[j].Ordinal
- }
- })
- bookSerie.SortedParts = sorted
- return gott.Tuple(args), nil
- }
- func GetBookSerie(id, language string, connection *sql.DB) (*BookSerie, error) {
- res, err := gott.
- NewResult(gott.Tuple{&network.Request{Id: id, Language: language, Connection: connection}, &Result{}}).
- Bind(createRepo).
- Bind(queryBookSerie).
- Map(parseBookSerie).
- Finish()
- if err != nil {
- return &BookSerie{}, err
- }
- return res.(gott.Tuple)[1].(*Result).Work.(*BookSerie), nil
- }
- func GetBookSerieOrdinals(id string, bookSerie *BookSerie, connection *sql.DB) (*BookSerie, error) {
- _, err := gott.
- NewResult(gott.Tuple{&network.Request{Id: id, Connection: connection}, &network.Result{}, bookSerie}).
- Bind(createOrdinalsRequest).
- Bind(network.DoRequest).
- Bind(network.HandleRequestError).
- Bind(network.ReadResponse).
- Bind(unmarshalOrdinals).
- Bind(sortOrdinals).
- // todo add is_read in parts
- Finish()
- if err != nil {
- return &BookSerie{}, err
- }
- return bookSerie, nil
- }
|