arte-plus7.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "regexp"
  8. "strings"
  9. "golang.org/x/net/html"
  10. )
  11. var mediaArtePlus7 = &Mediathek{
  12. Parse: parseArtePlus7,
  13. UrlRegexp: regexp.MustCompile("http://www.arte.tv/guide/"),
  14. UsageLine: "arteP7 url",
  15. Short: "helper for www.arte.tv/guide/...",
  16. Long: `
  17. input: http://www.arte.tv/guide/de/sendungen/....
  18. `,
  19. }
  20. func findPlayerJson(url string) (string, error) {
  21. plainHtmlResp, err := http.Get(url)
  22. if err != nil {
  23. return "", err
  24. }
  25. defer plainHtmlResp.Body.Close()
  26. d := html.NewTokenizer(plainHtmlResp.Body)
  27. for {
  28. // token type
  29. tokenType := d.Next()
  30. if tokenType == html.ErrorToken {
  31. if err := d.Err(); err == io.EOF {
  32. break
  33. } else {
  34. return "", fmt.Errorf("Error: Invalid HTML Token %s", err)
  35. }
  36. }
  37. token := d.Token()
  38. switch tokenType {
  39. case html.StartTagToken: // <tag>
  40. if strings.HasPrefix(token.String(), "<div class") {
  41. for _, attr := range token.Attr {
  42. if attr.Key == "arte_vp_url" {
  43. return attr.Val, nil
  44. }
  45. }
  46. }
  47. }
  48. }
  49. return "", fmt.Errorf("Error: PlayerJson-URL not found")
  50. }
  51. func findPlus7RtmpUrl(url string) (string, error) {
  52. // http://jsonviewer.stack.hu/#http://arte.tv/papi/tvguide/videos/stream/player/D/040347-001_PLUS7-D/ALL/ALL.json
  53. type Stream struct {
  54. Host string `json:"streamer"`
  55. Url string `json:"url"`
  56. Lang string `json:"versionLibelle"`
  57. // Width, Height, Bitrate int
  58. }
  59. type JsonPlayer struct {
  60. Streams map[string]Stream `json:"VSR"`
  61. // Streams map[string]interface{} `json:"VSR"`
  62. }
  63. type ApiResponse struct {
  64. // Search interface{} `json:"videoSearchParams"`
  65. Player JsonPlayer `json:"videoJsonPlayer"`
  66. }
  67. rtmpJsonResp, err := http.Get(url)
  68. if err != nil {
  69. return "", err
  70. }
  71. defer rtmpJsonResp.Body.Close()
  72. jsonDec := json.NewDecoder(rtmpJsonResp.Body)
  73. var jsonResp ApiResponse
  74. err = jsonDec.Decode(&jsonResp)
  75. if err != nil {
  76. return "", err
  77. }
  78. qualChain := []string{"RTMP_SQ_1", "RTMP_MQ_1", "RTMP_LQ_1"}
  79. for _, qual := range qualChain {
  80. stream, ok := jsonResp.Player.Streams[qual]
  81. if ok == true {
  82. composed := fmt.Sprintf("%smp4:%s", stream.Host, stream.Url)
  83. return composed, nil
  84. }
  85. // somehow http.Get != curl at this field..
  86. // if ok == true && stream.Lang == "Dt. Version" {
  87. // return stream.Url, nil
  88. // }
  89. }
  90. return "", fmt.Errorf("Error: rtmp-URL not found")
  91. }
  92. func parseArtePlus7(media *Mediathek, url string) {
  93. jsonUrl, err := findPlayerJson(url)
  94. if err != nil {
  95. fmt.Printf("Error during findPlayerJson: %s\n", err)
  96. setExitStatus(1)
  97. exit()
  98. }
  99. rtmpUrl, err := findPlus7RtmpUrl(jsonUrl)
  100. if err != nil {
  101. fmt.Printf("Error during findPlus7RtmpUrl: %s\n", err)
  102. setExitStatus(1)
  103. exit()
  104. }
  105. fmt.Println(rtmpUrl)
  106. }