diff --git a/cmd/aspiratv/config.go b/cmd/aspiratv/config.go
index 0609e1a..0808d18 100644
--- a/cmd/aspiratv/config.go
+++ b/cmd/aspiratv/config.go
@@ -5,6 +5,8 @@ import (
"fmt"
"log"
"os"
+ "os/exec"
+ "runtime"
"strings"
"time"
@@ -20,8 +22,34 @@ type Config struct {
ConfigFile string // Name of configuration file
WatchList []*providers.MatchRequest // Slice of show matchers
Headless bool // When true, no progression bar
- ConcurrentTasks int // Number of concurrent downloadss
+ ConcurrentTasks int // Number of concurrent downloads
Providers map[string]ProviderConfig
+ Provider string // Provider for dowload command
+ Destination string // Destination folder for dowload command
+
+}
+
+func (a *app) Initialize() {
+ a.ReadConfig(a.Config.ConfigFile)
+
+ // Check ans normalize configuration file
+ a.Config.Check()
+
+ // Check ffmpeg presence
+ var cmd *exec.Cmd
+ if runtime.GOOS == "windows" {
+ cmd = exec.Command("where", "ffmpeg")
+ } else {
+ cmd = exec.Command("which", "ffmpeg")
+ }
+ b, err := cmd.Output()
+ if err != nil {
+ log.Fatal("Missing ffmpeg on your system, it's required to download video files.")
+ }
+ a.ffmpeg = strings.Trim(strings.Trim(string(b), "\r\n"), "\n")
+ if a.Config.Debug {
+ log.Printf("FFMPEG path: %q", a.ffmpeg)
+ }
}
type ProviderConfig struct {
@@ -77,38 +105,32 @@ func WriteConfig() {
}
// ReadConfig read the JSON configuration file
-func ReadConfig(configFile string) (*Config, error) {
+func (a *app) ReadConfig(configFile string) error {
f, err := os.Open(configFile)
if err != nil {
- return nil, fmt.Errorf("Can't open configuration file: %v", err)
+ return fmt.Errorf("Can't open configuration file: %v", err)
}
defer f.Close()
- conf := &Config{}
d := json.NewDecoder(f)
- err = d.Decode(conf)
+ err = d.Decode(&a.Config)
if err != nil {
- return nil, fmt.Errorf("Can't decode configuration file: %v", err)
+ return fmt.Errorf("Can't decode configuration file: %v", err)
}
- return conf, nil
+ return nil
}
-// ReadConfigOrDie create a stub of config.json when it is missing from disk
-func ReadConfigOrDie(cli *Config) *Config {
- conf, err := ReadConfig(cli.ConfigFile)
- if err != nil {
- log.Fatalf("Fatal: %v", err)
- }
- // Set flags comming from CLI
- conf.Debug = cli.Debug
- conf.Force = cli.Force
- conf.ConfigFile = cli.ConfigFile
- conf.Headless = cli.Headless
- conf.ConcurrentTasks = cli.ConcurrentTasks
- return conf
-}
+// // ReadConfigOrDie create a stub of config.json when it is missing from disk
+// func ReadConfigOrDie(conf *Config) {
+// err := ReadConfig(conf.ConfigFile, conf)
+// if err != nil {
+// log.Fatalf("Fatal: %v", err)
+// }
+
+// }
// Check the configuration or die
func (c *Config) Check() {
+
// Expand paths
for d, p := range c.Destinations {
c.Destinations[d] = os.ExpandEnv(p)
diff --git a/cmd/aspiratv/config.json b/cmd/aspiratv/config.json
old mode 100755
new mode 100644
index 8f4e2f9..f44a1d4
--- a/cmd/aspiratv/config.json
+++ b/cmd/aspiratv/config.json
@@ -1,37 +1,25 @@
-{
- "PullInterval": "7h30m",
- "Destinations": {
- "Documentaires": "${HOME}/Videos/Documentaires",
- "Jeunesse": "${HOME}/Videos/Jeunesse",
- "Courts": "${HOME}/Videos/Courts"
- },
- "Providers": {
- "artetv": {
- "Enabled": false
- },
- "gulli":{
- "Enabled": false,
- "Settings":{
- "PreferedFormat": ".m38u"
- }
- },
- "francetv":{
- "Enabled": true
- }
- },
- "WatchList": [
- {
- "Show": "Si j'étais un animal",
- "Title": "",
- "Pitch": "",
- "Provider": "francetv",
- "Destination": "Jeunesse"
- },
- {
- "Show": "Oggy et les cafards",
- "Pitch": "",
- "Provider": "gulli",
- "Destination": "Jeunesse"
- }
- ]
-}
\ No newline at end of file
+{
+ "PullInterval": "7h",
+ "Destinations": {
+ "Documentaires": "${HOME}/Videos/Documentaires",
+ "Jeunesse": "${HOME}/Videos/Jeunesse",
+ "Courts": "${HOME}/Videos/Courts"
+ },
+ "Providers": {
+ "francetv": {
+ "enabled": true
+ },
+ "gulli": {
+ "enabled": false
+ }
+ },
+ "WatchList": [
+ {
+ "Show": "Lapins crétins",
+ "Title": "",
+ "Pitch": "",
+ "Provider": "francetv",
+ "Destination": "Jeunesse"
+ }
+ ]
+}
diff --git a/cmd/aspiratv/main.go b/cmd/aspiratv/main.go
index 59d08ac..0a7b1e2 100644
--- a/cmd/aspiratv/main.go
+++ b/cmd/aspiratv/main.go
@@ -35,6 +35,19 @@ var (
date = "unknown"
)
+type app struct {
+ Config Config
+ Stop chan bool
+ ffmpeg string
+ pb *mpb.Progress // Progress bars
+ worker *workers.WorkerPool
+ getter getter
+}
+
+type getter interface {
+ Get(uri string) (io.Reader, error)
+}
+
func main() {
fmt.Printf("%s: %v, commit %v, built at %v\n", filepath.Base(os.Args[0]), version, commit, date)
@@ -63,49 +76,61 @@ func main() {
}
}()
- cliConfig := &Config{}
-
- flag.BoolVar(&cliConfig.Debug, "debug", false, "Debug mode.")
- flag.BoolVar(&cliConfig.Force, "force", false, "Force media download.")
- flag.BoolVar(&cliConfig.Headless, "headless", false, "Headless mode. Progression bars are not displayed.")
- flag.StringVar(&cliConfig.ConfigFile, "config", "config.json", "Configuration file name.")
- flag.IntVar(&cliConfig.ConcurrentTasks, "max-tasks", runtime.NumCPU(), "Maximum concurrent downloads at a time.")
+ flag.BoolVar(&a.Config.Debug, "debug", false, "Debug mode.")
+ flag.BoolVar(&a.Config.Force, "force", false, "Force media download.")
+ flag.BoolVar(&a.Config.Headless, "headless", false, "Headless mode. Progression bars are not displayed.")
+ flag.StringVar(&a.Config.ConfigFile, "config", "config.json", "Configuration file name.")
+ flag.IntVar(&a.Config.ConcurrentTasks, "max-tasks", runtime.NumCPU(), "Maximum concurrent downloads at a time.")
+ flag.StringVar(&a.Config.Provider, "provider", "", "Provider to be used with download command. Possible values : artetv,francetv,gulli")
+ flag.StringVar(&a.Config.Destination, "destination", "", "Provider to be used with download command. Possible values : artetv,francetv,gulli")
flag.Parse()
log.SetOutput(os.Stderr)
- a.Initialize(cliConfig)
- a.Run(ctx)
-}
-
-func (a *app) Initialize(c *Config) {
- a.Config = ReadConfigOrDie(c)
-
- // Check ans normalize configuration file
- a.Config.Check()
-
- // Check ffmpeg presence
- var cmd *exec.Cmd
- if runtime.GOOS == "windows" {
- cmd = exec.Command("where", "ffmpeg")
- } else {
- cmd = exec.Command("which", "ffmpeg")
- }
- b, err := cmd.Output()
- if err != nil {
- log.Fatal("Missing ffmpeg on your system, it's required to download video files.")
+ a.Initialize()
+ if len(os.Args) < 2 {
+ flag.Usage()
+ os.Exit(1)
}
- a.ffmpeg = strings.Trim(strings.Trim(string(b), "\r\n"), "\n")
- if a.Config.Debug {
- log.Printf("FFMPEG path: %q", a.ffmpeg)
+ switch flag.Arg(0) {
+ case "download":
+ a.Download(ctx)
+ default:
+ a.Run(ctx)
}
}
-func (a *app) Run(ctx context.Context) {
+func (a *app) Download(ctx context.Context) {
+ if len(flag.Args()) < 2 {
+ flag.Usage()
+ os.Exit(1)
+ }
+
+ a.Config.Destinations = map[string]string{
+ "DL": os.ExpandEnv(a.Config.Destination),
+ }
+ a.Config.WatchList = []*providers.MatchRequest{
+ &providers.MatchRequest{
+ Destination: "DL",
+ Show: strings.ToLower(flag.Arg(1)),
+ Provider: a.Config.Provider,
+ },
+ }
a.worker = workers.New(ctx, a.Config.ConcurrentTasks, a.Config.Debug)
a.getter = http.DefaultClient
+ if a.Config.Provider == "" {
+ log.Println("Missing -provider PROVIDERNAME flag")
+ os.Exit(1)
+ }
+
+ p, ok := providers.List()[a.Config.Provider]
+ if !ok {
+ log.Printf("Unknown provider %q", a.Config.Provider)
+ os.Exit(1)
+ }
+
var pc *mpb.Progress
if !a.Config.Headless {
@@ -120,6 +145,20 @@ func (a *app) Run(ctx context.Context) {
))
}
+ a.PullShows(ctx, p, pc)
+ if !a.Config.Headless {
+ pc.Wait()
+ }
+}
+
+func (a *app) Run(ctx context.Context) {
+
+ a.worker = workers.New(ctx, a.Config.ConcurrentTasks, a.Config.Debug)
+ a.getter = http.DefaultClient
+
+ var pc *mpb.Progress
+ a.Config.Headless = true
+
activeProviders := int64(0)
for _, p := range providers.List() {
if a.Config.IsProviderActive(p.Name()) {
@@ -180,42 +219,43 @@ func (a *app) PullShows(ctx context.Context, p providers.Provider, pc *mpb.Progr
}
}()
- //log.Printf("Get shows list for %s", p.Name())
- pName := p.Name()
- shows, err := p.Shows(a.Config.WatchList)
- if err != nil {
- log.Printf("[%s] Can't get shows list of provider: %v", pName, err)
- return
- }
+ var providerBar *mpb.Bar
- seen := map[string]bool{}
- var bar *mpb.Bar
if !a.Config.Headless {
- bar = pc.AddBar(int64(len(shows)),
+ providerBar = pc.AddBar(0,
+ mpb.BarWidth(50),
mpb.PrependDecorators(
- // simple name decorator
- decor.Name(left(p.Name(), 20), decor.WC{W: 20 + 1, C: decor.DidentRight}),
- decor.CountersNoUnit(" %3d/%3d", decor.WC{W: 5 + 1, C: decor.DidentRight}),
- ))
- } else {
- log.Printf("[%s] %d shows available on server.", p.Name(), len(shows))
+ decor.Spinner([]string{"●∙∙", "∙●∙", "∙∙●", "∙●∙"}, decor.WCSyncSpace),
+ decor.Name(" Pulling "+p.Name()),
+ ),
+ mpb.AppendDecorators(
+ decor.Counters(0, " %d/%d"),
+ ),
+ )
+ if a.Config.Debug {
+ log.Printf("Provider Bar created %p", providerBar)
+ }
}
+ //log.Printf("Get shows list for %s", p.Name())
+ seen := map[string]bool{}
wg := sync.WaitGroup{}
+
+ showCount := int64(0)
showLoop:
- for id, s := range shows {
- if a.Config.Debug {
- log.Printf("PullShows %s, handling %d", p.Name(), id)
+ for s := range p.Shows(a.Config.WatchList) {
+ showCount++
+ if !a.Config.Headless {
+ providerBar.SetTotal(showCount, false)
}
if _, ok := seen[s.ID]; ok {
if !a.Config.Headless {
- bar.Increment()
+ // providerBar.Increment()
}
continue
}
seen[s.ID] = true
- d := a.Config.Destinations[s.Destination]
select {
case <-ctx.Done():
break showLoop
@@ -223,23 +263,25 @@ showLoop:
if ctx.Err() != nil {
break showLoop
}
+ d := a.Config.Destinations[s.Destination]
if a.Config.Force || a.MustDownload(p, s, d) {
if a.Config.Debug {
- log.Printf("PullShows %s, submitting %d", p.Name(), id)
+ log.Printf("[%s] submitting %d", p.Name(), showCount)
}
wg.Add(1)
- a.SubmitDownload(ctx, &wg, p, s, d, pc, bar)
+ a.SubmitDownload(ctx, &wg, p, s, d, pc, providerBar)
} else {
if !a.Config.Headless {
- bar.Increment()
+ providerBar.Increment()
} else {
log.Printf("[%s] %s already downloaded.", p.Name(), p.GetShowFileName(s))
}
}
+
}
}
if !a.Config.Headless {
- bar.SetTotal(int64(len(shows)), true)
+ providerBar.SetTotal(showCount, true)
}
if ctx.Err() == nil {
if a.Config.Debug {
@@ -268,7 +310,7 @@ func (a *app) MustDownload(p providers.Provider, s *providers.Show, d string) bo
}
func (a *app) SubmitDownload(ctx context.Context, wg *sync.WaitGroup, p providers.Provider, s *providers.Show, d string, pc *mpb.Progress, bar *mpb.Bar) {
- a.worker.Submit(func() {
+ go a.worker.Submit(func() {
a.DownloadShow(ctx, wg, p, s, d, pc, bar)
})
}
@@ -330,7 +372,6 @@ func (a *app) DownloadShow(ctx context.Context, wg *sync.WaitGroup, p providers.
var fileBar *mpb.Bar
if !a.Config.Headless {
- bar.Increment()
fileBar = pc.AddBar(100*1024*1024*1024,
mpb.BarWidth(3),
mpb.PrependDecorators(
@@ -352,7 +393,7 @@ func (a *app) DownloadShow(ctx context.Context, wg *sync.WaitGroup, p providers.
close(done)
if shouldDeleteFile {
for _, f := range files {
- log.Printf("[%s] Cancelled %s", p.Name(), p.GetShowFileName(s))
+ log.Printf("[%s] %s is cancelled.", p.Name(), p.GetShowFileName(s))
os.Remove(f)
}
}
@@ -364,6 +405,9 @@ func (a *app) DownloadShow(ctx context.Context, wg *sync.WaitGroup, p providers.
log.Printf("DownloadShow %d terminated", id)
}
wg.Done()
+ if !a.Config.Headless {
+ bar.Increment()
+ }
}()
err := os.MkdirAll(filepath.Dir(fn), 0777)
@@ -386,7 +430,9 @@ func (a *app) DownloadShow(ctx context.Context, wg *sync.WaitGroup, p providers.
url = master.BestQuality()
}
- //log.Println("Download url: ", url)
+ if a.Config.Debug {
+ log.Println("Download url: ", url)
+ }
params := []string{
"-loglevel", "quiet",
@@ -416,12 +462,10 @@ func (a *app) DownloadShow(ctx context.Context, wg *sync.WaitGroup, p providers.
err = cmd.Run()
if err != nil {
- log.Println(err)
shouldDeleteFile = true
return
}
if ctx.Err() != nil {
- log.Println(ctx.Err())
shouldDeleteFile = true
return
}
@@ -463,20 +507,7 @@ func (a *app) DownloadShow(ctx context.Context, wg *sync.WaitGroup, p providers.
log.Printf("[%s] Can't write %q's thumbnail: %v", p.Name(), p.GetShowFileName(s), err)
}
if a.Config.Headless || a.Config.Debug {
- log.Printf("[%s] %s already downloaded.", p.Name(), p.GetShowFileName(s))
+ log.Printf("[%s] %s downloaded.", p.Name(), p.GetShowFileName(s))
}
return
}
-
-type app struct {
- Config *Config
- Stop chan bool
- ffmpeg string
- pb *mpb.Progress // Progress bars
- worker *workers.WorkerPool
- getter getter
-}
-
-type getter interface {
- Get(uri string) (io.Reader, error)
-}
diff --git a/providers/artetv/artetv.go b/providers/artetv/artetv.go
index a70263d..7e4916b 100644
--- a/providers/artetv/artetv.go
+++ b/providers/artetv/artetv.go
@@ -4,17 +4,16 @@ import (
"encoding/json"
"fmt"
"io"
- "io/ioutil"
"log"
"net/url"
"path/filepath"
"regexp"
"sort"
- "strconv"
"strings"
+ "sync"
"time"
- "github.com/simulot/aspiratv/parsers/jscript"
+ "github.com/gocolly/colly"
"github.com/simulot/aspiratv/net/http"
"github.com/simulot/aspiratv/parsers/htmlparser"
@@ -34,8 +33,6 @@ func init() {
const (
arteIndex = "https://www.arte.tv"
arteCDN = "https://static-cdn.arte.tv"
- arteGuide = "https://www.arte.tv/guide/api/api/pages/fr/TV_GUIDE/?day=" // Day YY-MM-DD
- arteDetails = "https://api.arte.tv/api/player/v1/config/fr/%s?autostart=1&lifeCycle=1" // Player to get Video streams ProgID
arteCollection = "https://www.arte.tv/guide/api/api/zones/fr/collection_videos/?id=%s&page=%d" // Id and Page
arteSearch = "https://www.arte.tv/guide/api/api/zones/fr/listing_SEARCH/?page=1&limit=20&query=%s" // Search term
)
@@ -51,9 +48,11 @@ type getter interface {
type ArteTV struct {
getter getter
preferredVersions []string // versionCode List of version in order of preference VF,VA...
- preferredMedia string // mediaType mp4,hls
+ preferredQuality []string
+ preferredMedia string // mediaType mp4,hls
debug bool
htmlParserFactory *htmlparser.Factory
+ seenPrograms map[string]bool
}
// WithGetter inject a getter in FranceTV object instead of normal one
@@ -64,14 +63,68 @@ func WithGetter(g getter) func(p *ArteTV) {
}
}
+type throttler struct {
+ g getter
+ ticker *time.Ticker
+ throttle chan struct{}
+ burst int
+ rate time.Duration
+ stop chan struct{}
+ once sync.Once
+}
+
+func newThrottler(g getter, rate int, burst int) *throttler {
+ // lazy initialisation
+ return &throttler{
+ g: g, // The orriginal getter
+ burst: burst, // allow a burst of queries
+ rate: time.Second / time.Duration(rate), // Query
+ stop: make(chan struct{}), // Stop me if you can
+ }
+}
+
+func (t *throttler) init() {
+ t.throttle = make(chan struct{}, t.burst)
+ t.ticker = time.NewTicker(t.rate)
+ for i := 0; i < t.burst; i++ {
+ t.throttle <- struct{}{}
+ }
+ go func() {
+ defer t.ticker.Stop()
+ for {
+ select {
+ case <-t.stop:
+ return
+ case <-t.ticker.C:
+ t.throttle <- struct{}{}
+ default:
+ }
+ }
+
+ }()
+}
+
+func (t *throttler) Stop() {
+ <-t.stop
+}
+
+func (t *throttler) Get(uri string) (io.Reader, error) {
+ t.once.Do(t.init)
+ <-t.throttle
+ return t.g.Get(uri)
+}
+
// New setup a Show provider for Arte
func New(conf ...func(p *ArteTV)) (*ArteTV, error) {
+ throttler := newThrottler(http.DefaultClient, 2, 25)
p := &ArteTV{
- getter: http.DefaultClient,
+ getter: throttler,
//TODO: get preferences from config file
- preferredVersions: []string{"VF", "VOF", "VOF-STF", "VOSTF", "VF-STF"}, // "VF-STMF" "VA", "VA-STA"
+ preferredVersions: []string{"VF", "VF-STF", "VO-STF", "VO"}, // "VF-STMF" "VA", "VA-STA"
preferredMedia: "mp4",
+ preferredQuality: []string{"SQ", "XQ", "EQ", "HQ", "MQ"},
htmlParserFactory: htmlparser.NewFactory(),
+ seenPrograms: map[string]bool{},
}
for _, fn := range conf {
fn(p)
@@ -95,293 +148,315 @@ func withGetter(g getter) func(p *ArteTV) {
func (p ArteTV) Name() string { return "artetv" }
// Shows download the shows catalog from the web site.
-func (p *ArteTV) Shows(mm []*providers.MatchRequest) ([]*providers.Show, error) {
- shows := []*providers.Show{}
- log.Print("[artetv] Fetch Arte's new shows")
-
- replay, err := p.getReplayShows(mm)
- if err != nil {
- return nil, err
- }
- shows = append(shows, replay...)
-
- collections, err := p.getCollectionsShows(mm)
- if err != nil {
- return nil, err
- }
-
- shows = append(shows, collections...)
-
- return shows, nil
-}
+func (p *ArteTV) Shows(mm []*providers.MatchRequest) chan *providers.Show {
+ shows := make(chan *providers.Show)
+
+ go func() {
+ defer close(shows)
+ for _, m := range mm {
+ if m.Provider == p.Name() {
+ for s := range p.getShowList(m) {
+ s.Destination = m.Destination
+ shows <- s
+ }
-// browse all match request to handle those having a ShowID denoting an Arte collection ID
-// and invoke getCollection
-func (p *ArteTV) getCollectionsShows(mm []*providers.MatchRequest) ([]*providers.Show, error) {
- shows := []*providers.Show{}
- for _, m := range mm {
- if m.Provider == "artetv" && m.Playlist != "" {
- collection, err := p.getCollection(m.Playlist, m.Destination)
- if err != nil {
- log.Printf("[artetv] Can't fetch collection %q: %v", m.Playlist, err)
- continue
}
- shows = append(shows, collection...)
}
- }
- return shows, nil
-}
+ }()
-// getCollectionIDFromName retrieve collection's ID from its name
-// It returns the 1st encountered collection in result set
-func (p *ArteTV) getCollectionIDFromName(collection string) (string, error) {
+ return shows
+}
- if p.debug {
- log.Printf("[artetv] Query collection's ID: %q", collection)
- }
+func (p *ArteTV) getShowList(m *providers.MatchRequest) chan *providers.Show {
+ shows := make(chan *providers.Show)
- URL := fmt.Sprintf(arteSearch, url.PathEscape(collection))
- r, err := p.getter.Get(URL)
- if err != nil {
- return "", err
- }
- d := json.NewDecoder(r)
- result := &searchResults{}
- err = d.Decode(result)
- if err != nil {
- return "", err
- }
- for _, s := range result.Data {
- if strings.HasPrefix(s.ProgramID, "RC-") {
- return s.ProgramID, nil
- }
- }
- return "", fmt.Errorf("[artetv] Id for collection %q not found", collection)
-}
+ go func() {
+ defer close(shows)
-// get all Arte shows for the given collection ID
-func (p *ArteTV) getCollection(ColName string, destination string) ([]*providers.Show, error) {
+ //TODO: use user's preferred language
+ const apiSEARCH = "https://www.arte.tv/guide/api/emac/v3/fr/web/data/SEARCH_LISTING"
- ColID, err := p.getCollectionIDFromName(ColName)
- if err != nil {
- return nil, err
- }
+ u, err := url.Parse(apiSEARCH)
+ if err != nil {
+ log.Printf("[%s] Can't call search API: %q", p.Name(), err)
+ return
+ }
+ v := u.Query()
+ v.Set("imageFormats", "square,banner,landscape")
+ v.Set("query", m.Show)
+ v.Set("mainZonePage", "1")
+ v.Set("page", "1")
+ v.Set("limit", "100")
- shows := []*providers.Show{}
+ u.RawQuery = v.Encode()
- if p.debug {
- log.Printf("[artetv] Fetch collection: %q[%s]", ColName, ColID)
- }
- page := 1
+ var result APIResult
- for {
- URL := fmt.Sprintf(arteCollection, ColID, page)
- r, err := p.getter.Get(URL)
+ r, err := p.getter.Get(u.String())
if err != nil {
- return nil, err
+ log.Printf("[%s] Can't call search API: %q", p.Name(), err)
+ return
}
- d := json.NewDecoder(r)
- collection := &searchResults{}
- err = d.Decode(collection)
+
+ err = json.NewDecoder(r).Decode(&result)
if err != nil {
- return nil, err
+ log.Printf("[%s] Can't decode search API result: %q", err)
+ return
}
- for _, data := range collection.Data {
- s := &providers.Show{
- AirDate: time.Time{},
- Channel: "Arte",
- Category: "",
- Detailed: false,
- DRM: false,
- Duration: data.Duration.Duration(),
- Episode: "",
- ID: data.ProgramID,
- Pitch: strings.TrimSpace(data.Description),
- Season: "",
- Provider: "artetv",
- Show: strings.TrimSpace(collection.Link.Title),
- ShowURL: data.URL,
- StreamURL: "", // Must call GetShowStreamURL to get the show's URL
- ThumbnailURL: func(t thumbs) string {
- bestRes := -1
- bestURL := ""
- for _, r := range t.Resolutions {
- if r.Height*r.Width > bestRes {
- bestRes = r.Height * r.Width
- bestURL = r.URL
- }
- }
- return bestURL
- }(data.Images["landscape"]),
- Title: func() string {
- if len(data.Subtitle) > 0 {
- return strings.TrimSpace(data.Subtitle)
- }
- return strings.TrimSpace(data.Title)
- }(),
- Destination: destination,
+
+ matchedSeries := []Data{}
+ matchedShows := []Data{}
+
+ for _, d := range result.Data {
+ if strings.Contains(strings.ToLower(d.Title), m.Show) {
+ if d.Kind.IsCollection {
+ matchedSeries = append(matchedSeries, d)
+ } else {
+ matchedShows = append(matchedShows, d)
+ }
}
- setShowTitleEpisode(s, showInfo{
- title: data.Title,
- subTitle: data.Subtitle,
- })
- shows = append(shows, s)
}
- if len(collection.NextPage) == 0 {
- break
+
+ if len(matchedSeries) > 0 {
+ for _, d := range matchedSeries {
+ for s := range p.getSerie(d) {
+ shows <- s
+ }
+ }
}
- page++
- }
- if p.debug {
- log.Printf("[artetv] Collection: %q has %d shows", ColName, len(shows))
- }
- return shows, nil
+ }()
+ return shows
}
-// parse guide page to get brocasted shows.
-// Note for the first run (in service mode), we collect 3 weeks of guide
-func (p *ArteTV) getReplayShows(mm []*providers.MatchRequest) ([]*providers.Show, error) {
- var dateStart time.Time
+//https://www.arte.tv/guide/api/emac/v3/fr/web/programs/044892-008-A/?
+//https:// www.arte.tv/guide/api/emac/v3/fr/web/data/COLLECTION_VIDEOS/?collectionId=RC-014408&page=1&limit=100
+//https://api-cdn.arte.tv/ api/emac/v3/fr/web/data/COLLECTION_VIDEOS/?collectionId=RC-015842&page=2&limit=12
+var (
+ parseCollectionInURL = regexp.MustCompile(`RC-\d+`)
+ parseSeason = regexp.MustCompile(`Saison (\d+)`)
+)
- shows := []*providers.Show{}
- if runCounter == 0 {
- // Start search 3 weeks in the past
- dateStart = time.Now().Truncate(24 * time.Hour).Add(-3 * 7 * 24 * time.Hour)
- } else {
- // Start today
- dateStart = time.Now().Truncate(24 * time.Hour)
- }
+func (p *ArteTV) getSerie(d Data) chan *providers.Show {
+ shows := make(chan *providers.Show)
- dateEnd := time.Now().Truncate(24 * time.Hour).Add(24 * time.Hour)
+ go func() {
+ defer close(shows)
- for d := dateStart; d.Before(dateEnd); d = d.Add(24 * time.Hour) {
- ss, err := p.getGuide(mm, d)
- if err != nil {
- return nil, err
- }
- shows = append(shows, ss...)
- }
- runCounter++
- return shows, nil
-}
+ //TODO: use user's preferred language
+ const apiSEARCH = "https://www.arte.tv/guide/api/emac/v3/fr/web/data/COLLECTION_VIDEOS/?collectionId=%s&page=%d&limit=12"
-// getGuide get Arte's guide of programs for the given date
-func (p *ArteTV) getGuide(mm []*providers.MatchRequest, d time.Time) ([]*providers.Show, error) {
- if p.debug {
- log.Printf("[artetv] Fetch guide for date: %s", d.Format("06-01-02"))
- }
- url := arteGuide + d.Format("06-01-02")
- r, err := p.getter.Get(url)
- if err != nil {
- return nil, err
- }
- decoder := json.NewDecoder(r)
- guide := &guide{}
- err = decoder.Decode(guide)
- if err != nil {
- return nil, err
- }
+ collectionIDs := map[string]string{"": d.ProgramID} // Collection per season
+ seasonSearched := false
+
+ collectionLoop:
+ for len(collectionIDs) > 0 {
+ seasons := []string{}
+ for k := range collectionIDs {
+ seasons = append(seasons, k)
+ }
+ sort.Strings(seasons)
+ u := fmt.Sprintf(apiSEARCH, collectionIDs[seasons[0]], 1)
+
+ // Loop collections's pages
+ for len(u) > 0 {
+
+ u2, err := url.Parse(u)
+ if err != nil {
+ log.Printf("[%s] Can't get collection: %q", p.Name(), err)
+ return
+ }
+ u2.Host = "www.arte.tv"
+ u2.Path = "guide/api/emac/v3/fr/web/data/COLLECTION_VIDEOS"
+ u = u2.String()
+
+ if p.debug {
+ log.Println(u)
+ }
- shows := []*providers.Show{}
+ r, err := p.getter.Get(u)
+ if err != nil {
+ log.Printf("[%s] Can't get collection: %q", p.Name(), err)
+ return
+ }
- for _, z := range guide.Zones {
- if z.Code.Name == "listing_TV_GUIDE" {
- for _, data := range z.Data {
- s := &providers.Show{
- AirDate: func(ds []tsGuide) time.Time {
- if len(ds) > 0 {
- return ds[0].Time()
+ var result APIResult
+ err = json.NewDecoder(r).Decode(&result)
+ if err != nil {
+ log.Printf("[%s] Can't get decode collection: %q", p.Name(), err)
+ return
+ }
+
+ if len(result.Data) == 0 {
+ // A collection of collection (a serie, indeed) enrty hasn't any Data. We have to fetch collections for each season
+ if seasonSearched {
+ log.Printf("[%s] Can't found collection with ID(%s): %q", p.Name(), d.ProgramID, err)
+ return
+ }
+ seasonSearched = true
+
+ // No results on a collection ID? this means this is a collection of collections...
+ // Let's scrap the web page to get the collection list, most likely all seasons
+ delete(collectionIDs, "")
+
+ parser := p.htmlParserFactory.New()
+
+ parser.OnHTML("a.next-navbar__slide", func(e *colly.HTMLElement) {
+ var season, id string
+ m := parseSeason.FindAllStringSubmatch(e.Text, -1)
+ if len(m) == 1 {
+ season = m[0][1]
}
- return time.Time{}
- }(data.BroadcastDates),
- Channel: "Arte",
- Category: "",
- Detailed: false,
- DRM: false,
- Duration: data.Duration.Duration(),
- Episode: "",
- ID: data.ProgramID,
- Pitch: strings.TrimSpace(data.ShortDescription),
- Season: "",
- Show: strings.TrimSpace(data.Title),
- Provider: "artetv",
- ShowURL: data.URL,
- StreamURL: "", // Must call GetShowStreamURL to get the show's URL
- ThumbnailURL: func(t thumbs) string {
- bestRes := -1
- bestURL := ""
- for _, r := range t.Resolutions {
- if r.Height*r.Width > bestRes {
- bestRes = r.Height * r.Width
- bestURL = r.URL
- }
+ m = parseCollectionInURL.FindAllStringSubmatch(e.Attr("href"), -1)
+ if len(m) == 2 {
+ id = m[1][0]
}
- return bestURL
- }(data.Images["landscape"]),
- // Title: strings.TrimSpace(d.Subtitle),
- }
- if providers.IsShowMatch(mm, s) {
- setShowTitleEpisode(s, showInfo{
- title: data.Title,
- subTitle: data.Subtitle,
+ collectionIDs[season] = id
})
- shows = append(shows, s)
+
+ err := parser.Visit(d.URL)
+ if err != nil {
+ log.Printf("[%s] Can't get collection: %q", p.Name(), err)
+ return
+ }
+ continue collectionLoop
}
+
+ for _, ep := range result.Data {
+ show := &providers.Show{
+ ID: ep.ProgramID,
+ Show: d.Title, //Takes collection's title
+ Title: ep.Subtitle,
+ Pitch: ep.ShortDescription,
+ ShowURL: ep.URL,
+ Season: seasons[0],
+ }
+
+ img := getBestImage(ep.Images, "square")
+ if len(img) == 0 {
+ img = getBestImage(ep.Images, "landscape")
+ }
+ show.ThumbnailURL = img
+ err := p.GetShowInfo(show)
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ setEpisodeFormTitle(show, ep.Title)
+ shows <- show
+ }
+
+ u = result.NextPage
+
}
+ delete(collectionIDs, seasons[0]) // Season on top of the stack is done.
+ }
+ }()
+
+ return shows
+}
+
+var (
+ parseTitleSeasonEpisode = regexp.MustCompile(`([^-]+) - Saison (\d+) \((\d+)\/\d+\)`)
+ parseTitle = regexp.MustCompile(`([^-]+) - (.+)`)
+)
+
+func setEpisodeFormTitle(show *providers.Show, t string) {
+
+ m := parseTitleSeasonEpisode.FindAllStringSubmatch(t, -1)
+ if len(m) > 0 {
+ show.Show = m[0][1]
+ show.Season = m[0][2]
+ show.Episode = m[0][3]
+ return
+ }
+ m = parseTitleSeasonEpisode.FindAllStringSubmatch(show.Title, -1)
+ if len(m) > 0 {
+ show.Show = m[0][1]
+ show.Season = ""
+ show.Episode = ""
+ return
+ }
+ if show.Title == "" {
+ show.Title = t
+ }
+}
+
+// getBestImage retreive the url for the image of type "protrait/banner/landscape..." with the highest resolution
+func getBestImage(images Images, t string) string {
+ image, ok := images[t]
+ if !ok {
+ return ""
+ }
+
+ bestResolution := 0
+ bestURL := ""
+ for _, r := range image.Resolutions {
+ _ = 1
+ res := r.H * r.W
+ if res > bestResolution {
+ bestURL = r.URL
+ bestResolution = res
}
}
- return shows, nil
+ if bestResolution == 0 {
+ return ""
+ }
+ return bestURL
}
-var reArteSeries = regexp.MustCompile(`(?P
.*\S)\s*\((?P\d+)\/(?P\d+)\)`)
+// GetShowFileName return a file name with a path that is compatible with PLEX server:
+// ShowName/Season NN/ShowName - sNNeMM - Episode title
+// Show and Episode names are sanitized to avoid problem when saving on the file system
+func (p *ArteTV) GetShowFileName(s *providers.Show) string {
+ err := p.GetShowInfo(s)
+ if err != nil {
+ return ""
+ }
+ var showPath, seasonPath, episodePath string
+ showPath = providers.PathNameCleaner(s.Show)
-// Get episode number from the title pattern (episode/number of episodes) in the title
-// If found, the pattern (x/y) is removed from title
-// Set the Title with Show when empty
-func setShowTitleEpisode(s *providers.Show, info showInfo) {
- s.Show = info.title
- s.Title = info.subTitle
- s.Episode = ""
+ if s.Season == "" {
+ seasonPath = "Season " + s.AirDate.Format("2006")
+ } else {
+ seasonPath = "Season " + providers.Format2Digits(s.Season)
+ }
- m := reArteSeries.FindStringSubmatch(s.Show)
- if m != nil {
- s.Show = m[1]
- s.Episode = m[2]
+ if s.Episode == "" {
+ episodePath = providers.FileNameCleaner(s.Show) + " - " + s.AirDate.Format("2006-01-02")
} else {
- s.Episode = episodeFromID(s.ID)
+ episodePath = providers.FileNameCleaner(s.Show) + " - s" + providers.Format2Digits(s.Season) + "e" + providers.Format2Digits(s.Episode)
}
- if len(s.Title) == 0 {
- // Fill the episode title with Show title and episode number for having different files name
- s.Title = s.Show + " (e" + providers.Format2Digits(s.Episode) + ")"
+ if s.Title == "" || s.Title == s.Show {
+ episodePath += " - " + s.ID + ".mp4"
+ } else {
+ episodePath += " - " + providers.FileNameCleaner(s.Title) + ".mp4"
}
+ return filepath.Join(showPath, seasonPath, episodePath)
+}
+
+// GetShowFileNameMatcher return a file pattern of this show
+// used for detecting already got episode even when episode or season is different
+func (p *ArteTV) GetShowFileNameMatcher(s *providers.Show) string {
+ return p.GetShowFileName(s)
}
+// https://api.arte.tv/api/player/v1/config/fr/083668-012-A?autostart=1&lifeCycle=1
+
+const arteDetails = "https://api.arte.tv/api/player/v1/config/fr/%s?autostart=1&lifeCycle=1" // Player to get Video streams ProgID
+
// GetShowStreamURL return the show's URL, a mp4 file
func (p *ArteTV) GetShowStreamURL(s *providers.Show) (string, error) {
if s.StreamURL != "" {
return s.StreamURL, nil
}
- if p.debug {
- log.Printf("Fetch video url for %q, %q", s.Show, s.Title)
- }
- url := fmt.Sprintf(arteDetails, s.ID)
- r, err := p.getter.Get(url)
- if err != nil {
- return "", fmt.Errorf("Can't get show's detailled information: %v", err)
- }
-
- d := json.NewDecoder(r)
- i := &player{}
- err = d.Decode(&i)
+ err := p.GetShowInfo(s)
if err != nil {
- return "", fmt.Errorf("Can't decode show's detailled information: %v", err)
+ return "", err
}
- s.StreamURL = p.getBestVideo(i.VideoJSONPlayer.VSR)
-
return s.StreamURL, nil
}
@@ -391,70 +466,26 @@ func (p *ArteTV) GetShowInfo(s *providers.Show) error {
if s.Detailed {
return nil
}
- r, err := p.getter.Get(s.ShowURL)
- if err != nil {
- return err
- }
- info, err := readDetails(r)
- if err != nil {
- return err
+ url := fmt.Sprintf(arteDetails, s.ID)
+ if p.debug {
+ log.Println(url)
}
- s.AirDate = info.airDate
- s.Season = info.season
- setShowTitleEpisode(s, info)
- return nil
-}
-
-type showInfo struct {
- season string
- airDate time.Time
- title string
- subTitle string
-}
-
-// readDetails returns the structure that contains shows details
-
-func readDetails(r io.Reader) (showInfo, error) {
- info := showInfo{}
- b, err := ioutil.ReadAll(r)
+ r, err := p.getter.Get(url)
if err != nil {
- return info, err
+ return fmt.Errorf("Can't get show's detailled information: %v", err)
}
-
- o, err := jscript.ParseObjectAtAnchor(b, regexp.MustCompile(`"zones":\[\{`))
+ player := playerAPI{}
+ err = json.NewDecoder(r).Decode(&player)
if err != nil {
- return info, err
+ return fmt.Errorf("Can't decode show's detailled information: %v", err)
}
- if dd := o.Property("data"); dd != nil {
- for _, d := range dd.Ar {
- if t := d.Property("title"); t != nil {
- info.title = strings.TrimSpace(t.String())
- }
- if t := d.Property("subtitle"); t != nil {
- info.subTitle = strings.TrimSpace(t.String())
- }
- if a := d.Property("availability"); a != nil {
- if t := a.Property("startDay"); t != nil {
- d, err := time.Parse("2006-01-02", t.String())
- if err == nil {
- info.airDate = d
- }
- }
- }
- if cc := d.Property("credits"); cc != nil {
- for _, c := range cc.Ar {
- if code := c.Property("code"); code != nil && code.String() == "PRODUCTION_YEAR" {
- y := c.Property("values").Strings()
- info.season = y[0]
- }
- }
- }
- }
- }
+ s.StreamURL = p.getBestVideo(player.VideoJSONPlayer.VSR)
+ s.AirDate = time.Time(player.VideoJSONPlayer.VRA)
+ s.Detailed = true
- return info, nil
+ return nil
}
type mapStrInt map[string]uint64
@@ -465,144 +496,16 @@ type mapStrInt map[string]uint64
// - Stream quality, the highest possible
// - Preferred format
// The URL's stream with the best score is returned
-func (p *ArteTV) getBestVideo(ss map[string]streamInfo) string {
- scores := mapStrInt{}
- sortedResolution := getPlayerResolutions(ss)
-
- for k, s := range ss {
- scores[k] = p.getStreamScore(s, reverseSliceIndex(getResolutionKey(s), sortedResolution))
- }
-
- scoreSlice := sortMapStrInt(scores)
- return ss[scoreSlice[0]].URL
-}
-
-func getPlayerResolutions(ss map[string]streamInfo) []string {
- scoreResolution := mapStrInt{}
- for _, s := range ss {
- p := uint64(s.Height) * uint64(s.Width) * uint64(s.Bitrate)
- scoreResolution[getResolutionKey(s)] = p
- }
- return sortMapStrInt(scoreResolution)
-}
-
-func getResolutionKey(s streamInfo) string {
- return strconv.Itoa(s.Width) + "*" + strconv.Itoa(s.Height) + "*" + strconv.Itoa(s.Bitrate)
-}
-
-func (p *ArteTV) getStreamScore(s streamInfo, resolutionIndex uint64) uint64 {
- grade := uint64(0)
-
- // Best grade for the preferred version
- grade += reverseSliceIndex(s.VersionCode, p.preferredVersions) * 1000000
-
- // Then best resolution
- grade += resolutionIndex * 1000
-
- // Add points for the preferred format
- if s.MediaType == p.preferredMedia {
- grade += 10
- }
- return grade
-}
-
-// sortMapStrInt return a slice of string in the order int
-func sortMapStrInt(m mapStrInt) []string {
- type kv struct {
- k string
- v uint64
- }
- s := make([]kv, len(m))
- i := 0
- for k, v := range m {
- s[i] = kv{k: k, v: v}
- i++
- }
- sort.Slice(s, func(i, j int) bool {
- return s[i].v > s[j].v
- })
- r := make([]string, len(m))
- for i, v := range s {
- r[i] = v.k
- }
- return r
-}
-func sliceIndex(k string, ls []string) uint64 {
- for i, s := range ls {
- if s == k {
- return uint64(i + 1)
- }
- }
- return 0
-}
-
-func reverseSliceIndex(k string, ls []string) uint64 {
- r := sliceIndex(k, ls)
- if r == 0 {
- return r
- }
- return uint64(len(ls)+1) - r
-
-}
-
-func episodeFromID(ID string) string {
- b := ""
- for _, c := range ID {
- if c >= '0' && c <= '9' {
- b += string(c)
+func (p *ArteTV) getBestVideo(ss map[string]StreamInfo) string {
+ for _, r := range p.preferredQuality {
+ for _, v := range p.preferredVersions {
+ for _, s := range ss {
+ if s.Quality == r && s.VersionCode == v {
+ return s.URL
+ }
+ }
}
}
- for len(b) > 0 && b[0] == '0' {
- b = b[1:]
- }
- return b
-}
-
-// GetShowFileName return a file name with a path that is compatible with PLEX server:
-// ShowName/Season NN/ShowName - sNNeMM - Episode title
-// Show and Episode names are sanitized to avoid problem when saving on the file system
-func (p *ArteTV) GetShowFileName(s *providers.Show) string {
- if !s.Detailed {
- p.GetShowInfo(s)
- }
- switch {
- case s.Season == "" && s.Episode == "" && s.AirDate.IsZero():
- // Following Plex naming convention for Specials show https://support.plex.tv/articles/200220707-naming-tv-show-specials/
- return filepath.Join(
- providers.PathNameCleaner(s.Show),
- "Specials",
- providers.FileNameCleaner(s.Show)+" - s00e"+episodeFromID(s.ID)+" - "+providers.FileNameCleaner(s.Title)+".mp4",
- )
- case s.Season == "" && s.Episode == "" && !s.AirDate.IsZero():
- // Follow Plex naming convention https://support.plex.tv/articles/200381053-naming-date-based-tv-shows/
- return filepath.Join(
- providers.PathNameCleaner(s.Show),
- "Season "+strconv.Itoa(s.AirDate.Year()),
- providers.FileNameCleaner(s.Show)+" - s"+strconv.Itoa(s.AirDate.Year())+"e"+episodeFromID(s.ID)+" - "+providers.FileNameCleaner(s.Title)+".mp4",
- )
- case s.Season != "" && s.Episode == "" && !s.AirDate.IsZero():
- // When episode is missing, use the ID as episode number
- return filepath.Join(
- providers.PathNameCleaner(s.Show),
- "Season "+providers.Format2Digits(s.Season),
- providers.FileNameCleaner(s.Show)+" - s"+s.Season+"e"+episodeFromID(s.ID)+" - "+providers.FileNameCleaner(s.Title)+".mp4",
- )
- }
- // Normal case: https://support.plex.tv/articles/200220687-naming-series-season-based-tv-shows/
- return filepath.Join(
- providers.PathNameCleaner(s.Show),
- "Season "+providers.Format2Digits(s.Season),
- providers.FileNameCleaner(s.Show)+" - s"+providers.Format2Digits(s.Season)+"e"+providers.Format2Digits(s.Episode)+" - "+providers.FileNameCleaner(s.Title)+".mp4",
- )
-}
-
-// GetShowFileNameMatcher return a file pattern of this show
-// used for detecting already got episode even when episode or season is different
-func (ArteTV) GetShowFileNameMatcher(s *providers.Show) string {
- return filepath.Join(
- providers.PathNameCleaner(s.Show),
- "*",
- providers.FileNameCleaner(s.Show)+" - * - "+providers.FileNameCleaner(s.Title)+".mp4",
- )
+ return ""
}
diff --git a/providers/artetv/artetv_test.go b/providers/artetv/artetv_test.go
deleted file mode 100644
index 7b0d6fb..0000000
--- a/providers/artetv/artetv_test.go
+++ /dev/null
@@ -1,314 +0,0 @@
-package artetv
-
-import (
- "encoding/json"
- "os"
- "path/filepath"
- "reflect"
- "testing"
- "time"
-
- "github.com/simulot/aspiratv/net/http/httptest"
-)
-
-func readPlayer() (*player, error) {
- f, err := os.Open(filepath.Join("testdata", "player.json"))
- if err != nil {
- return nil, err
- }
- defer f.Close()
- d := json.NewDecoder(f)
- player := &player{}
- err = d.Decode(player)
- if err != nil {
- return nil, err
- }
-
- return player, nil
-}
-func TestBestStream(t *testing.T) {
- p, err := New()
- if err != nil {
- t.Error(err)
- return
- }
-
- player, err := readPlayer()
- if err != nil {
- t.Error(err)
- return
- }
-
- s := p.getBestVideo(player.VideoJSONPlayer.VSR)
- if s != player.VideoJSONPlayer.VSR["HTTPS_SQ_1"].URL {
- t.Errorf("Unexpected value, got %v", player.VideoJSONPlayer.VSR[s])
- }
-}
-
-func Test_sortMapStrInt(t *testing.T) {
- type args struct {
- m mapStrInt
- }
- tests := []struct {
- name string
- args args
- want []string
- }{
- {
- "empty",
- args{
- mapStrInt{},
- },
- []string{},
- },
- {
- "one",
- args{
- mapStrInt{"one": 1},
- },
- []string{"one"},
- },
- {
- "two",
- args{
- mapStrInt{"one": 1, "two": 2},
- },
- []string{"two", "one"},
- },
- {
- "three",
- args{
- mapStrInt{"one": 1, "two": 2, "three": 3},
- },
- []string{"three", "two", "one"},
- },
- {
- "three-2",
- args{
- mapStrInt{"two": 2, "three": 3, "one": 1},
- },
- []string{"three", "two", "one"},
- },
- {
- "three-3",
- args{
- mapStrInt{"three": 3, "one": 1, "two": 2},
- },
- []string{"three", "two", "one"},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := sortMapStrInt(tt.args.m); !reflect.DeepEqual(got, tt.want) {
- t.Errorf("sortMapStrInt() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func Test_sliceIndex(t *testing.T) {
- type args struct {
- k string
- ls []string
- }
- tests := []struct {
- name string
- args args
- want uint64
- }{
- {
- "empty-key-list",
- args{"", []string{}},
- 0,
- },
- {
- "empty-key",
- args{"", []string{"foo", "bar"}},
- 0,
- },
- {
- "empty-list",
- args{"foo", []string{}},
- 0,
- },
- {
- "test-notfound",
- args{"notfound", []string{"one", "two", "three"}},
- 0,
- },
- {
- "test-one",
- args{"one", []string{"one", "two", "three"}},
- 1,
- },
- {
- "test-two",
- args{"two", []string{"one", "two", "three"}},
- 2,
- },
- {
- "test-three",
- args{"three", []string{"one", "two", "three"}},
- 3,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := sliceIndex(tt.args.k, tt.args.ls); got != tt.want {
- t.Errorf("sliceIndex() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func Test_reverseSliceIndex(t *testing.T) {
- type args struct {
- k string
- ls []string
- }
- tests := []struct {
- name string
- args args
- want uint64
- }{
- {
- "empty-key-list",
- args{"", []string{}},
- 0,
- },
- {
- "empty-key",
- args{"", []string{"foo", "bar"}},
- 0,
- },
- {
- "empty-list",
- args{"foo", []string{}},
- 0,
- },
- {
- "test-notfound",
- args{"notfound", []string{"one", "two", "three"}},
- 0,
- },
- {
- "test-one",
- args{"one", []string{"one", "two", "three"}},
- 3,
- },
- {
- "test-two",
- args{"two", []string{"one", "two", "three"}},
- 2,
- },
- {
- "test-three",
- args{"three", []string{"one", "two", "three"}},
- 1,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := reverseSliceIndex(tt.args.k, tt.args.ls); got != tt.want {
- t.Errorf("reverseSliceIndex() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func Test_getGuide(t *testing.T) {
- getter := httptest.New(httptest.WithConstantFile(filepath.Join("testdata", "guide.json")))
-
- p, err := New(withGetter(getter))
- if err != nil {
- t.Errorf("Unexpected error: %v", err)
- return
- }
-
- ss, err := p.getGuide(nil, time.Time{})
- if err != nil {
- t.Errorf("Unexpected error: %v", err)
- return
- }
-
- if len(ss) != 31 {
- t.Errorf("Expecting %d shows, got %d", 31, len(ss))
- }
-}
-
-func Test_getPlayerResolutions(t *testing.T) {
- player, err := readPlayer()
- if err != nil {
- t.Error(err)
- return
- }
- res := getPlayerResolutions(player.VideoJSONPlayer.VSR)
- if len(res) != 4 {
- t.Errorf("Expected resolution number %d, got %d", 4, len(res))
- }
-}
-
-func TestArteTV_getStreamScore(t *testing.T) {
-
- player, err := readPlayer()
- if err != nil {
- t.Error(err)
- return
- }
-
- sortedResolution := getPlayerResolutions(player.VideoJSONPlayer.VSR)
-
- type args struct {
- s streamInfo
- resolutionIndex uint64
- }
- tests := []struct {
- name string
- args args
- want uint64
- }{
- {
- "HTTPS_SQ_1",
- args{
- player.VideoJSONPlayer.VSR["HTTPS_SQ_1"],
- reverseSliceIndex(getResolutionKey(player.VideoJSONPlayer.VSR["HTTPS_SQ_1"]), sortedResolution),
- },
- 1004010,
- },
- {
- "HLS_XQ_1",
- args{
- player.VideoJSONPlayer.VSR["HLS_XQ_1"],
- reverseSliceIndex(getResolutionKey(player.VideoJSONPlayer.VSR["HLS_XQ_1"]), sortedResolution),
- },
- 1004000,
- },
- {
- "HTTPS_HQ_1",
- args{
- player.VideoJSONPlayer.VSR["HTTPS_HQ_1"],
- reverseSliceIndex(getResolutionKey(player.VideoJSONPlayer.VSR["HTTPS_HQ_1"]), sortedResolution),
- },
- 1002010,
- },
- {
- "HTTPS_SQ_2",
- args{
- player.VideoJSONPlayer.VSR["HTTPS_SQ_2"],
- reverseSliceIndex(getResolutionKey(player.VideoJSONPlayer.VSR["HTTPS_SQ_2"]), sortedResolution),
- },
- 4010,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- p := &ArteTV{
- preferredVersions: []string{"VF", "VOF", "VOSTF", "VF-STF"},
- preferredMedia: "mp4",
- }
- if got := p.getStreamScore(tt.args.s, tt.args.resolutionIndex); got != tt.want {
- t.Errorf("ArteTV.getStreamScore() = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/providers/artetv/getdetails_test.go b/providers/artetv/getdetails_test.go
deleted file mode 100644
index bdb7dc7..0000000
--- a/providers/artetv/getdetails_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package artetv
-
-import (
- "os"
- "path/filepath"
- "reflect"
- "testing"
- "time"
-
- "github.com/alecthomas/repr"
-)
-
-func mustParse(t *testing.T, f string, d string) time.Time {
- date, err := time.Parse(f, d)
- if err != nil {
- t.Fatal(err)
- }
- return date
-}
-func Test_readDetails(t *testing.T) {
- expected := showInfo{
- airDate: mustParse(t, "2006-01-02", "2018-07-02"),
- season: "2017",
- title: "La minute vieille",
- subTitle: "Pulsion irréstistible",
- }
-
- f, err := os.Open(filepath.Join("testdata", "minute.html.txt"))
- if err != nil {
- t.Fatal(err)
- return
- }
- defer f.Close()
-
- o, err := readDetails(f)
- if err != nil {
- t.Error(err)
- return
- }
- if !reflect.DeepEqual(expected, o) {
- t.Errorf("Expected %s, got %s", repr.String(expected), repr.String(o))
- }
-}
diff --git a/providers/artetv/testdata/collection.json b/providers/artetv/testdata/collection.json
deleted file mode 100644
index 43fa8ae..0000000
--- a/providers/artetv/testdata/collection.json
+++ /dev/null
@@ -1 +0,0 @@
-{"code":{"name":"collection_videos","id":"RC-013500"},"type":null,"title":"Accueil","displayOptions":{"template":"default","layout":"default","theme":null},"link":{"page":"RC-013500","title":"Astronomie : voyage vers les étoiles !","url":"https://www.arte.tv/fr/videos/RC-013500/astronomie-voyage-vers-les-etoiles/"},"nextPage":"https://api-cdn.arte.tv/api/emac/v3/fr/web/zones/collection_videos?id=RC-013500&page=2","contextPage":null,"data":[{"id":"076598-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"076598-000-A","url":"https://www.arte.tv/fr/videos/076598-000-A/destination-pluton/","title":"Destination Pluton","subtitle":null,"description":"Grâce aux données recueillies par la sonde New Horizons, Pluton se dévoile dans ce documentaire fouillé, superbement mis en images. Parmi les premières surprises, on note les similitudes semblant se dessiner entre Pluton et la planète Mars...","images":{"landscape":{"caption":"Pluton","resolutions":[{"url":"https://static-cdn.arte.tv/resize/HmtafehdJ8-a61MjovRpb-Ltpik=/200x113/smart/filters:strip_icc()/apios/Img_data/2/076598-000-A_2490066.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/QYQvnpDrrkcTS2t13Oe3ddPGla0=/400x225/smart/filters:strip_icc()/apios/Img_data/2/076598-000-A_2490066.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/Q2Y514ZY-klg3qvhWcqtnFfJskw=/620x350/smart/filters:strip_icc()/apios/Img_data/2/076598-000-A_2490066.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/xcnA0oF0KGJ8A-joXlObQHM58Po=/720x406/smart/filters:strip_icc()/apios/Img_data/2/076598-000-A_2490066.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/Hs8nFHLZvV360pT8mu015sltRDw=/940x530/smart/filters:strip_icc()/apios/Img_data/2/076598-000-A_2490066.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/cLe1JMePvWkr1NGc_bx9CJpkdb4=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/2/076598-000-A_2490066.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":2983,"childrenCount":null,"geoblocking":{"code":"EUR_DE_FR","label":""},"availability":null},{"id":"062227-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"062227-000-A","url":"https://www.arte.tv/fr/videos/062227-000-A/thomas-pesquet-objectif-mars/","title":"Thomas Pesquet : objectif Mars","subtitle":null,"description":"Pour envoyer des missions habitées sur Mars, de nombreux défis attendent encore la science. Un état des lieux passionnant dans les pas du spationaute Thomas Pesquet, de son séjour en orbite à son retour sur Terre.","images":{"landscape":{"caption":"Thomas Pesquet dans l'espace, à l'extérieur de l'ISS.","resolutions":[{"url":"https://static-cdn.arte.tv/resize/KAcG1sZNj8Fe5_hBAO1zv4C4in0=/200x113/smart/filters:strip_icc()/apios/Img_data/11/062227-000-A_2438032.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/77YW0KItjw7uFR6PIHefgMFw0Z4=/400x225/smart/filters:strip_icc()/apios/Img_data/11/062227-000-A_2438032.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/O_W-LEPGLHHAnU4SzZlYfy2OSsk=/620x350/smart/filters:strip_icc()/apios/Img_data/11/062227-000-A_2438032.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/S-bfJJEomJ46pHhwrfBfizrHE50=/720x406/smart/filters:strip_icc()/apios/Img_data/11/062227-000-A_2438032.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/JUYwGRoBC35mk0NJbVLmNNInJ2o=/940x530/smart/filters:strip_icc()/apios/Img_data/11/062227-000-A_2438032.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/NKcg9bqZPZSMlHjOICWFmXTgS4k=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/11/062227-000-A_2438032.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":5621,"childrenCount":null,"geoblocking":{"code":"SAT","label":""},"availability":null},{"id":"082521-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"082521-000-A","url":"https://www.arte.tv/fr/videos/082521-000-A/mysterieux-trous-noirs/","title":"Mystérieux trous noirs","subtitle":null,"description":"L'étude des trous noirs, objets les plus énigmatiques de notre cosmos, révolutionne notre compréhension de l'univers. Une découverte spectaculaire de ces singularités physiques, guidée par l'astrophysicienne Janna Levin.","images":{"landscape":{"caption":"Le trou noir déformant l'espace-temps.","resolutions":[{"url":"https://static-cdn.arte.tv/resize/vx0dUxxUy8g8oUxTfAN_DhFF4rA=/200x113/smart/filters:strip_icc()/apios/Img_data/17/082521-000-A_2438039.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/e7EQ50nfWy3Fpmiyy6hTar1S3uI=/400x225/smart/filters:strip_icc()/apios/Img_data/17/082521-000-A_2438039.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/aV2FxcbkVK_50X1uxJUc1JQftbg=/620x350/smart/filters:strip_icc()/apios/Img_data/17/082521-000-A_2438039.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/AFJ6tVhRhuXBtyEXtQHPhW09534=/720x406/smart/filters:strip_icc()/apios/Img_data/17/082521-000-A_2438039.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/64JGU-FHlB8UGCPqGnnfkExN9F0=/940x530/smart/filters:strip_icc()/apios/Img_data/17/082521-000-A_2438039.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/0c_2vntDFmm_kdaTdrotEPOesuI=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/17/082521-000-A_2438039.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":6723,"childrenCount":null,"geoblocking":{"code":"EUR_DE_FR","label":""},"availability":null},{"id":"077322-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"077322-000-A","url":"https://www.arte.tv/fr/videos/077322-000-A/dernier-voyage-vers-saturne/","title":"Dernier voyage vers Saturne","subtitle":null,"description":"En retraçant l'aventure spatiale de la sonde Cassini, ce documentaire foisonnant d'images exceptionnelles révèle les secrets de Saturne, la plus majestueuse des planètes du système solaire. ","images":{"landscape":{"caption":"Illustration de la sonde Cassini, l'un des engins spatiaux les plus élaborés jamais conçu par l'homme.","resolutions":[{"url":"https://static-cdn.arte.tv/resize/wo4SE-hwuvhNq0eGCdkYCof8FVc=/200x113/smart/filters:strip_icc()/apios/Img_data/22/077322-000-A_2426575.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/e92BGEvzXJp3h73zjnux-OAdkZ4=/400x225/smart/filters:strip_icc()/apios/Img_data/22/077322-000-A_2426575.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/uubRcVvKsGnDWMWYmrtaq-QuQ1c=/620x350/smart/filters:strip_icc()/apios/Img_data/22/077322-000-A_2426575.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/SCR-rZiDlDaisydw7MmWYeyrANs=/720x406/smart/filters:strip_icc()/apios/Img_data/22/077322-000-A_2426575.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/wjB-l3Tqvs53Kvc62CPP4dTQvYs=/940x530/smart/filters:strip_icc()/apios/Img_data/22/077322-000-A_2426575.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/-fPc5aZ2nD-myUezXs6ARm2eIEA=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/22/077322-000-A_2426575.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3194,"childrenCount":null,"geoblocking":{"code":"EUR_DE_FR","label":""},"availability":null},{"id":"053954-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"053954-000-A","url":"https://www.arte.tv/fr/videos/053954-000-A/messagers-de-l-univers/","title":"Messagers de l'univers","subtitle":"Les neutrinos","description":"Seraient-ils la clef de l'univers ? Récemment découverts, les neutrinos gardent une grande part de mystère. Rencontre avec des chercheurs qui tentent de percer le secret de ces particules fantômes.","images":{"landscape":{"caption":"neutrinos","resolutions":[{"url":"https://static-cdn.arte.tv/resize/wKmlX6KX0YhbEshoorDs8JcmC54=/200x113/smart/filters:strip_icc()/apios/Img_data/28/053954-000-A_2483726.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/_itf4TYCk0cIPZo_BhrvxCqRn74=/400x225/smart/filters:strip_icc()/apios/Img_data/28/053954-000-A_2483726.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/uX0YylRaT8iXBqcanoZirHB9QYQ=/620x350/smart/filters:strip_icc()/apios/Img_data/28/053954-000-A_2483726.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/uDEAiQ2nnJRvGS23OuHl_dW7qYQ=/720x406/smart/filters:strip_icc()/apios/Img_data/28/053954-000-A_2483726.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/2QeW97aGOyHY9GZafoqx8utAB8Y=/940x530/smart/filters:strip_icc()/apios/Img_data/28/053954-000-A_2483726.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/1uc4snm3EbZe7Z7DOTHlfPflMUI=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/28/053954-000-A_2483726.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3109,"childrenCount":null,"geoblocking":{"code":"ALL","label":""},"availability":null},{"id":"066394-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"066394-000-A","url":"https://www.arte.tv/fr/videos/066394-000-A/aube-cosmique-la-naissance-des-premieres-etoiles/","title":"Aube cosmique : la naissance des premières étoiles","subtitle":null,"description":"Que s'est-il passé entre le big bang et l'univers tel que nous le connaissons aujourd'hui ? Une captivante enquête doublée d'un époustouflant voyage dans l'aube cosmique. ","images":{"landscape":{"caption":"Aube cosmique : la naissance des premières étoiles","resolutions":[{"url":"https://static-cdn.arte.tv/resize/YWOehaKI1rcJUsGMWcIATjKBTtg=/200x113/smart/filters:strip_icc()/apios/Img_data/29/066394-000-A_1805638.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/StTsk4xDAQlrsYvGmY0r3dNupfY=/400x225/smart/filters:strip_icc()/apios/Img_data/29/066394-000-A_1805638.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/EdnYvmQwOxBOXPrxc3GYM_u4VCE=/620x350/smart/filters:strip_icc()/apios/Img_data/29/066394-000-A_1805638.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/eDI74PSjeSu4VOGBWZJLzh__0hw=/720x406/smart/filters:strip_icc()/apios/Img_data/29/066394-000-A_1805638.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/oakgqVUWYrEEIODb2R3M7k3U11I=/940x530/smart/filters:strip_icc()/apios/Img_data/29/066394-000-A_1805638.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/VtzPvfaLtjjalyWJpzFsEx6EjjQ=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/29/066394-000-A_1805638.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3103,"childrenCount":null,"geoblocking":{"code":"DE_FR","label":""},"availability":null},{"id":"067802-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"067802-000-A","url":"https://www.arte.tv/fr/videos/067802-000-A/mission-mars/","title":"Mission Mars","subtitle":"Le programme spatial européen entre rêves et réalité","description":"La mission \"ExoMars\" signe l'alliance de l'Europe et de la Russie dans l'exploration spatiale. Plongée au coeur d'un projet fascinant qui suscite fantasmes et controverses. ","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/_e9GURZuF1azj_6RdHMiD0wdRD4=/200x113/smart/filters:strip_icc()/apios/Img_data/22/067802-000-A_2079128.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/u_MC7lh0QVmkPihKEgkN4gAP5w0=/400x225/smart/filters:strip_icc()/apios/Img_data/22/067802-000-A_2079128.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/HK6MRvQijqBA9Uq2NHbLDmwRk2c=/620x350/smart/filters:strip_icc()/apios/Img_data/22/067802-000-A_2079128.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/ZGUKYNV6aNbk_ayUWiKLhWbc9D4=/720x406/smart/filters:strip_icc()/apios/Img_data/22/067802-000-A_2079128.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/wxtnTvVrqm83nq0pw_dDiI4jfdE=/940x530/smart/filters:strip_icc()/apios/Img_data/22/067802-000-A_2079128.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/RtatoX3Kdj7D5Xuc_Pb9TmoeU9w=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/22/067802-000-A_2079128.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3152,"childrenCount":null,"geoblocking":{"code":"ALL","label":""},"availability":null},{"id":"061652-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"061652-000-A","url":"https://www.arte.tv/fr/videos/061652-000-A/l-odyssee-rosetta/","title":"L'Odyssée Rosetta","subtitle":"900 jours sur une comète","description":"Douze ans après son lancement dans l'espace, la sonde spatiale européenne Rosetta a achevé son voyage en s'écrasant sur la comète \"Tchouri\" le 30 septembre 2016. Plongée au coeur d'une aventure scientifique et humaine hors du commun.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/iJVVXlZcV2adXOm99fFSnnyN36c=/200x113/smart/filters:strip_icc()/apios/Img_data/14/061652-000-A_1951224.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/itFEcm4IUE4UG2m1m0V1F-_1LUs=/400x225/smart/filters:strip_icc()/apios/Img_data/14/061652-000-A_1951224.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/h2FZ_5UTjsSNdrAZ67GUawIGsWc=/620x350/smart/filters:strip_icc()/apios/Img_data/14/061652-000-A_1951224.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/GyjRc9rNyR0JKKs-cZUV8NAp4xs=/720x406/smart/filters:strip_icc()/apios/Img_data/14/061652-000-A_1951224.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/b0UK3azpNzgkkGrtZHAPrJLHyoA=/940x530/smart/filters:strip_icc()/apios/Img_data/14/061652-000-A_1951224.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/ZDW4w_sx_VbRbVDM5l5AgHs0r9k=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/14/061652-000-A_1951224.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":5535,"childrenCount":null,"geoblocking":{"code":"SAT","label":""},"availability":null},{"id":"064441-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"064441-000-A","url":"https://www.arte.tv/fr/videos/064441-000-A/thomas-pesquet-profession-astronaute/","title":"Thomas Pesquet - Profession astronaute","subtitle":null,"description":"Le 15 novembre 2016, Thomas Pesquet s'envole de Baïkonour pour sa première mission dans l’espace. Ce documentaire fait vivre au plus près du jeune Français l'intense année de préparation qui a précédé son départ pour la station spatiale internationale.","images":{"landscape":{"caption":"Thomas Pesquet","resolutions":[{"url":"https://static-cdn.arte.tv/resize/CFvBGMdqHmH-jNE00Cv_E-uzPbU=/200x113/smart/filters:strip_icc()/apios/Img_data/15/064441-000-A_1836341.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/_shnpoAfrSbHWD2JDsaVxgvEC_Y=/400x225/smart/filters:strip_icc()/apios/Img_data/15/064441-000-A_1836341.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/GaEW8iCqfcZOJBlReaf4vTiXxSs=/620x350/smart/filters:strip_icc()/apios/Img_data/15/064441-000-A_1836341.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/deMHlPl9QzrsNiBirxxkGurfpgU=/720x406/smart/filters:strip_icc()/apios/Img_data/15/064441-000-A_1836341.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/wFKZNFYY3hyuBI6gkrVYMXLeg6Q=/940x530/smart/filters:strip_icc()/apios/Img_data/15/064441-000-A_1836341.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/2tQiM4X2zcBmpBjESNV_VyRvxsk=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/15/064441-000-A_1836341.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":5584,"childrenCount":null,"geoblocking":{"code":"SAT","label":""},"availability":null},{"id":"043872-000-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"043872-000-A","url":"https://www.arte.tv/fr/videos/043872-000-A/le-mystere-de-la-matiere-noire/","title":"Le mystère de la matière noire","subtitle":null,"description":"La matière noire, inconnue indétectable dans nos modèles physiques, peuplerait massivement le cosmos. Pour la première fois, un film montre la folle quête scientifique dont elle est l'objet. Un thriller haletant qui nous emmène à l'aube d'une révolution scientifique et métaphysique équivalente à celle de Copernic ou de Galilée.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/A17OILfyQefPqvs9XcxIFKn2y5I=/200x113/smart/filters:strip_icc()/apios/Img_data/21/043872-000_dunklematerie_02.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/TkHCHeUxkxHmDQmKtkSUdFnE_jA=/400x225/smart/filters:strip_icc()/apios/Img_data/21/043872-000_dunklematerie_02.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/4YWu0OeZl0ohgCZX1tiR6f7n2bo=/620x350/smart/filters:strip_icc()/apios/Img_data/21/043872-000_dunklematerie_02.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/K7Iq8uXgVIXJGtb7Nj6Xt0nIvUs=/720x406/smart/filters:strip_icc()/apios/Img_data/21/043872-000_dunklematerie_02.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/WGscHDup_ADvMQnGvQB6yCDiyqg=/940x530/smart/filters:strip_icc()/apios/Img_data/21/043872-000_dunklematerie_02.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/J50Z6rU-kMdz0D66UzlTNCUfVs0=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/21/043872-000_dunklematerie_02.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3295,"childrenCount":null,"geoblocking":{"code":"EUR_DE_FR","label":""},"availability":null},{"id":"081327-057-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"081327-057-A","url":"https://www.arte.tv/fr/videos/081327-057-A/de-l-eau-liquide-sur-mars-une-decouverte-tant-attendue/","title":"De l’eau liquide sur Mars : une découverte tant attendue","subtitle":null,"description":"Le 25 juillet dernier, des scientifiques italiens ont prouvé l’existence d’un lac d’eau à l’état liquide sur Mars. Située à 1,5 km de profondeur vers le pôle sud de la planète, cette étendue d’eau de 20 km a pu être observée grâce au radar MARSIS, installé sur la sonde Mars Express en orbite depuis 2003. Cette découverte relance l’espoir d’une possible vie sur Mars.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/5sMUSKlee8x1jqbvCBq1slFvp6U=/trim:top-left:30/200x113/smart/filters:strip_icc()/apios/Img_data/23/081327-057-A_1580.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/xIEt9ofsuaX9MiBMp6VnQ-BVxUc=/trim:top-left:30/400x225/smart/filters:strip_icc()/apios/Img_data/23/081327-057-A_1580.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/l6lHC20DyV3vqwRrXmR5ntgZvFU=/trim:top-left:30/620x350/smart/filters:strip_icc()/apios/Img_data/23/081327-057-A_1580.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/XKfYV-BasO8w5roCicN0f3SgUd8=/trim:top-left:30/720x406/smart/filters:strip_icc()/apios/Img_data/23/081327-057-A_1580.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/kwuH-WV2axxjI5nkboJudh_q5VM=/trim:top-left:30/940x530/smart/filters:strip_icc()/apios/Img_data/23/081327-057-A_1580.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/gGYmZADR_DEBytUESP_zGTMXDEM=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/23/081327-057-A_1580.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":190,"childrenCount":null,"geoblocking":{"code":"ALL","label":""},"availability":null},{"id":"078162-011-A_SHOW_ARTE_NEXT_FR_fr","type":"teaser","kind":{"code":"SHOW","label":"Programme"},"programId":"078162-011-A","url":"https://www.arte.tv/fr/videos/078162-011-A/xenius/","title":"Xenius","subtitle":"Les éclipses : Soleil et Lune jouent à cache-cache","description":"Les éclipses solaires et lunaires constituent des événements rares et fascinants. Comment les mouvements de ces corps célestes ont-ils, jadis, révolutionné les sciences ? Et que nous apprennent-ils aujourd’hui ? Xenius part en quête de réponses dans l'un des plus anciens planétariums du monde encore en activité.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/sVoBCR5XCQNtL5UE1JQ0nJ8w03Y=/200x113/smart/filters:strip_icc()/apios/Img_data/19/078162-011-A_2423093.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/K3mk5MpnsGG7kBnyqJkPQtrfi_Q=/400x225/smart/filters:strip_icc()/apios/Img_data/19/078162-011-A_2423093.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/pWT7O51eo6NpYMWnBOuCrxWyAGo=/620x350/smart/filters:strip_icc()/apios/Img_data/19/078162-011-A_2423093.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/aj68EFskSNUsliO_-ELyzmXiB-8=/720x406/smart/filters:strip_icc()/apios/Img_data/19/078162-011-A_2423093.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/lrBWwH72Pz2kSgFnEt5mJUVr5K0=/940x530/smart/filters:strip_icc()/apios/Img_data/19/078162-011-A_2423093.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/ALxTfA9bo3JzFnSf6-j4s_35LKU=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/19/078162-011-A_2423093.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":1563,"childrenCount":null,"geoblocking":{"code":"SAT","label":""},"availability":null}]}
\ No newline at end of file
diff --git a/providers/artetv/testdata/guide.json b/providers/artetv/testdata/guide.json
deleted file mode 100644
index 1c746d9..0000000
--- a/providers/artetv/testdata/guide.json
+++ /dev/null
@@ -1 +0,0 @@
-{"id":"TV_GUIDE_fr_web","page":"TV_GUIDE","language":"fr","support":"web","level":1,"parent":null,"alternativeLanguages":[{"code":"fr","label":"Français","page":"TV_GUIDE","url":"https://www.arte.tv/fr/guide/20180815/","title":"Programme TV 15/08/2018. Emission, série, film, documentaire | ARTE"},{"code":"de","label":"Deutsch","page":"TV_GUIDE","url":"https://www.arte.tv/de/guide/20180815/","title":"TV-Programm 15/08/2018. Alle Sendungen auf einen Blick | ARTE"}],"images":null,"url":"https://www.arte.tv/fr/guide/20180815/","title":"Programme TV 15/08/2018. Emission, série, film, documentaire | ARTE","description":"Pour connaître les rendez-vous incontournables de la chaîne, consultez le guide TV d'ARTE. Renseignez-vous sur les programmes 3 semaines en avance.","slug":"20180815","stats":{"xiti":{"page_name":"TV_Guide","chapter1":null,"chapter2":null,"chapter3":null,"x1":"fr","x2":"Article","s2":3,"siteId":"582046","env_work":"prod","search_keywords":null}},"zones":[{"code":{"name":"highlights_TV_GUIDE","id":null},"type":"highlight","title":"","displayOptions":{"template":"default","layout":"default","theme":null},"link":null,"nextPage":null,"contextPage":"TV_GUIDE","data":[{"id":"047384-000-A_fr","programId":"047384-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/047384-000-A/diabolo-menthe/","title":"Diabolo menthe","subtitle":null,"shortDescription":"Premier film (et premier coup d'éclat) pour Diane Kurys, qui signe une chronique subtile de l'adolescence.","fullDescription":"Au début des années 1960, deux soeurs font l'apprentissage de la vie, de l'amour, de la politique... Premier film (et premier coup d'éclat) pour Diane Kurys, qui signe avec \"Diabolo menthe\" une chronique subtile de l'adolescence.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/7Iq7npyOFwQadsZUmexB_tW1EUA=/200x113/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/S9IJ45UqJAwMFfinjBDiRK45CuE=/400x225/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/1Kq_vSqDL3l5KM7Mn4BWHVYTUqM=/620x350/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/EjkiKvpomolNpaZCo_6h_Yfa7Vo=/720x406/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/xfEFVcoRIT1ubGn48ELyR8dtubk=/940x530/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/74HUDjNSBe7U6jzhPO-73py8Rr8=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":5714,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T18:55:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"048641-006-A_fr","programId":"048641-006-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/048641-006-A/jesus-et-l-islam-4-7/","title":"Jésus et l’islam (4/7)","subtitle":"L’exil du Prophète","shortDescription":"Pourquoi l'exil de Mahomet de La Mecque à Médine (l’hégire) fonde-t-il l’ère musulmane ?","fullDescription":"Pourquoi Jésus occupe-t-il une place exceptionnelle dans le Coran ? Enquête sur les origines et la genèse de l’islam. Quatrième volet : pourquoi l'exil de Mahomet de La Mecque à Médine (l’hégire) fonde-t-il l’ère musulmane ? Permet-il d’opérer la distinction entre les sourates mecquoises et les sourates médinoises ? Peut-on reconstituer la chronologie du Coran ?","images":{"landscape":{"caption":"L'EXIL DU PROPHETE","resolutions":[{"url":"https://static-cdn.arte.tv/resize/fkrTwdsy29GcNEcjHDNWM6MJNAE=/200x113/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/g3eTyTo_b1QZza9Huv-dzxckLGw=/400x225/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/bqjk8wgFfY9Y770uRipcPlzcj9c=/620x350/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/wGTJkDzcDPrdXcf1XnJe0bV7Tvw=/720x406/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/fZU2S2Nm5Z67fC19WnTCU6R4KWI=/940x530/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/g9DDe0c0_ZCo4z5AQKYEfsZN99E=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":3134,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T20:30:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"048641-007-A_fr","programId":"048641-007-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/048641-007-A/jesus-et-l-islam-5-7/","title":"Jésus et l’islam (5/7)","subtitle":"Mahomet et la Bible","shortDescription":"Pourquoi le Coran fait-il référence à la Bible hébraïque et aux textes chrétiens, notamment les apocryphes ?","fullDescription":"Pourquoi Jésus occupe-t-il une place exceptionnelle dans le Coran ? Les auteurs de \"Corpus Christi\" enquêtent sur les origines et la genèse de l’islam auprès de vingt-six chercheurs du monde entier. Cinquième volet : le Coran fait de nombreuses références à la Bible hébraïque et aux textes chrétiens, notamment les évangiles apocryphes. D’où Mahomet tirait-il ce savoir ?","images":{"landscape":{"caption":"JESUS ET L'ISLAM // MAHOMET ET LA BIBLE","resolutions":[{"url":"https://static-cdn.arte.tv/resize/881xX81-YzphEFeQR-GXOUx2YkQ=/200x113/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/GRg9MP3bzbfpbxaY0aqDBK-juGc=/400x225/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/5aX1lTyHbfy2cUDEUv20B7dflZQ=/620x350/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/zxqB-pC_n__9a-9UGKqlEwTfrcY=/720x406/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/bi7s99mrkYn76rimxvEuWfBvmWQ=/940x530/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/7ONeCXQUIRq6sHE-VrOK4-K26PI=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":3159,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T21:25:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null}]},{"code":{"name":"listing_TV_GUIDE","id":null},"type":"guide_list","title":"","displayOptions":{"template":"default","layout":"default","theme":null},"link":null,"nextPage":null,"contextPage":"TV_GUIDE","data":[{"id":"040498-000-A_fr","programId":"040498-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/040498-000-A/augustin-dumay-interprete-felix-mendelssohn-bartholdy/","title":"Augustin Dumay interprète Felix Mendelssohn Bartholdy","subtitle":null,"shortDescription":"Dirigé par Augustin Dumay, l'Orchestre royal de chambre de Wallonie interprète deux pièces de Felix Mendelssohn.","fullDescription":"L'Orchestre royal de chambre de Wallonie a été créé en 1958. À sa tête depuis 2005, le violoniste Augustin Dumay s'emploie à élargir le répertoire de la formation. Au programme de ce concert événement, deux pièces de Felix Mendelssohn, le \"Concerto n°1 en ré mineur pour violon et orchestre\" et \"Les Hébrides, ouverture en si mineur op. 26\".","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/MuVNzO6i6jp0HwlDs7lc1axnEqQ=/200x113/smart/filters:strip_icc()/apios/Img_data/15/090222_maestrodumay_01.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/4GAszojtI_qN6Jaiq6AB7swh0r0=/400x225/smart/filters:strip_icc()/apios/Img_data/15/090222_maestrodumay_01.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/PRjmSgy39frcXFpQ1P4HJVvnobA=/620x350/smart/filters:strip_icc()/apios/Img_data/15/090222_maestrodumay_01.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/snrHmeNfkDh0-kBhaGwl9xxKvSQ=/720x406/smart/filters:strip_icc()/apios/Img_data/15/090222_maestrodumay_01.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/S2bUcF3SXwKA1tZqKoiChvehVvQ=/940x530/smart/filters:strip_icc()/apios/Img_data/15/090222_maestrodumay_01.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/rgAEBEJAWPyPrBiXoCZrbGUkF7Q=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/15/090222_maestrodumay_01.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":2439,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T03:00:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"069853-005-A_fr","programId":"069853-005-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/069853-005-A/xenius/","title":"Xenius","subtitle":"Faut-il bannir les voitures des centres villes ?","shortDescription":"Particules fines, dioxyde d’azote : l'essentiel de la pollution en ville provient de la circulation automobile.","fullDescription":"Dans les centres-villes, la pollution aux particules fines et au dioxyde d’azote est en majeure partie due à la circulation automobile. Quelle est l’ampleur de cette pollution et comment l’éviter ? Les présentateurs de \"Xenius\" mènent l’enquête à Paris.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/EbuQIIQApKz5Lzl8zEQv2GUlZsc=/200x113/smart/filters:strip_icc()/apios/Img_data/15/069853-005-A_2022102.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/vuw8OGZL4WxuBtr_S9uedKJH0d0=/400x225/smart/filters:strip_icc()/apios/Img_data/15/069853-005-A_2022102.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/hjJdk8vrZAfTd7S_G_tvfdY2id8=/620x350/smart/filters:strip_icc()/apios/Img_data/15/069853-005-A_2022102.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/vxe3kWyG3icop5S1WPF5jKgetXA=/720x406/smart/filters:strip_icc()/apios/Img_data/15/069853-005-A_2022102.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/l6YY0T54y-jZX3kjgglcSufYysU=/940x530/smart/filters:strip_icc()/apios/Img_data/15/069853-005-A_2022102.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/jM3M7JA5ft65sSw-ylh6OwNjELg=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/15/069853-005-A_2022102.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":1557,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T03:45:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"030273-635-A_fr","programId":"030273-635-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/030273-635-A/arte-reportage/","title":"ARTE Reportage","subtitle":"Le génocide des Rohingyas / Sénégal : une série pour le droit des femmes","shortDescription":"Birmanie : Rohingyas, un génocide à huis clos / Sénégal : une série TV pour les droits des femmes","fullDescription":"\"Birmanie : Rohingyas, un génocide à huis clos\" - Viols, pillages, villages bombardés et incendiés... une étape vient d’être franchie dans la répression dont sont victimes depuis des décennies les Rohingyas. \"Sénégal : une série TV pour le droit des femmes\" - La série \"C’est la vie\" aborde les tabous de la société africaine, avec l’objectif de faire évoluer les mentalités et peut-être, un jour, les lois.","images":{"landscape":{"caption":"Une famille en fuite, parmi des dizaines de milliers, tente la traversée du fleuve qui mène sur les rives du Bangladesh...","resolutions":[{"url":"https://static-cdn.arte.tv/resize/QcDkFDCH50dLwdE_sNm-a1AwYe4=/200x113/smart/filters:strip_icc()/apios/Img_data/24/030273-635-A_2202964.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/XnRVUFzq8q1w8k9lH-sxxTDyAaE=/400x225/smart/filters:strip_icc()/apios/Img_data/24/030273-635-A_2202964.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/60EjLUQd1zMpII7M6_ckaLV3ba4=/620x350/smart/filters:strip_icc()/apios/Img_data/24/030273-635-A_2202964.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/uhfHCCKUdXswIE_EaqgIKpux3cM=/720x406/smart/filters:strip_icc()/apios/Img_data/24/030273-635-A_2202964.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/u3bFnGGhapmHJQdGkllp4j12mGI=/940x530/smart/filters:strip_icc()/apios/Img_data/24/030273-635-A_2202964.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/eoz2ggCcaH2soMW9sOD4q6F-9Ys=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/24/030273-635-A_2202964.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3177,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T04:15:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"079059-163-A_fr","programId":"079059-163-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/079059-163-A/arte-journal-junior/","title":"ARTE Journal Junior","subtitle":null,"shortDescription":"Le JT matinal et quotidien de six minutes pour les 10-14 ans.","fullDescription":"Le JT matinal et quotidien de six minutes pour les 10-14 ans.","images":{"landscape":{"caption":"ARTE Journal Junior","resolutions":[{"url":"https://static-cdn.arte.tv/resize/lvuXRSD6xCxt1OfM8oezU2ENZNw=/200x113/smart/filters:strip_icc()/apios/Img_data/8/079059-163-A_2466622.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/V7YHdaiEEpvtUfhJTUXfbrPH_a0=/400x225/smart/filters:strip_icc()/apios/Img_data/8/079059-163-A_2466622.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/6iWngUN0WhuC1d973hlSHEKuBt0=/620x350/smart/filters:strip_icc()/apios/Img_data/8/079059-163-A_2466622.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/j_8zEhDQqtJ2MbI7mBbyVNO7zz0=/720x406/smart/filters:strip_icc()/apios/Img_data/8/079059-163-A_2466622.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/zUpwbXCCwC1aSS4TsbS6ucbDgcA=/940x530/smart/filters:strip_icc()/apios/Img_data/8/079059-163-A_2466622.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/3ufWkrOROgz7xFQmgl35NvSKjtQ=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/8/079059-163-A_2466622.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":365,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T05:10:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"072418-007-F_fr","programId":"072418-007-F","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/072418-007-F/360-geo/","title":"360° Géo","subtitle":"Colombie, les fous volants de l’Amazonie","shortDescription":"En Colombie, d'anciens Douglas DC-3 déservent les localités reculées de la forêt amazonienne.","fullDescription":"En Colombie, certains villages reculés d'Amazonie subsistent grâce au transport de passagers et de marchandises par des Douglas DC-3, un modèle d’avion fabriqué entre 1935 et 1946.","images":{"landscape":{"caption":" ","resolutions":[{"url":"https://static-cdn.arte.tv/resize/UzBpubDeB5pa5Krx8yiU2YQoQRk=/200x113/smart/filters:strip_icc()/apios/Img_data/26/072418-007-F_2216614.JPG","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/Q8u0KO9WOf_RqRKkYINz-geyPms=/400x225/smart/filters:strip_icc()/apios/Img_data/26/072418-007-F_2216614.JPG","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/VuPCdjQ0zNlsbhW0DmYscYH7HdA=/620x350/smart/filters:strip_icc()/apios/Img_data/26/072418-007-F_2216614.JPG","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/7VmxgG4v-UZPXjy2CSfYk8WG0tM=/720x406/smart/filters:strip_icc()/apios/Img_data/26/072418-007-F_2216614.JPG","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/1n4VViUtei4WAUGO6UH_gtP9u34=/940x530/smart/filters:strip_icc()/apios/Img_data/26/072418-007-F_2216614.JPG","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/jpcJN6_3VpoyGMqRIDXav1zTtEU=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/26/072418-007-F_2216614.JPG"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":2564,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T05:15:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"078727-092-A_fr","programId":"078727-092-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/078727-092-A/invitation-au-voyage/","title":"Invitation au voyage","subtitle":"Edgar Degas à Naples / Granada / Nantes","shortDescription":"Naples - Granada, splendeur du Nicaragua - Le château des ducs de Bretagne, à Nantes.","fullDescription":"Linda Lorin nous emmène à la découverte de trois lieux de notre patrimoine artistique, culturel et naturel. Dans ce numéro : à Naples, Edgar Degas découvre le mouvement ; Granada, splendeur du Nicaragua ; \"L’incontournable\" : le château des ducs de Bretagne, à Nantes.","images":{"landscape":{"caption":"Naples","resolutions":[{"url":"https://static-cdn.arte.tv/resize/1OD7ZaOG_aVnG0USruAGLwqSZvY=/200x113/smart/filters:strip_icc()/apios/Img_data/18/078727-092-A_2397636.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/r5hpAIgOfCCHyWTB5uyvA5j9K30=/400x225/smart/filters:strip_icc()/apios/Img_data/18/078727-092-A_2397636.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/OJ0duAC08onpQt8ywmX_MsU18YM=/620x350/smart/filters:strip_icc()/apios/Img_data/18/078727-092-A_2397636.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/mysgWfY3ta0kmvqsGA4TQRGCD3Y=/720x406/smart/filters:strip_icc()/apios/Img_data/18/078727-092-A_2397636.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/shMLPkptxO8Q_qyxfXUnbO1rfX8=/940x530/smart/filters:strip_icc()/apios/Img_data/18/078727-092-A_2397636.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/ICmlTHbr8qaHIlFFlDidBDr7ke0=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/18/078727-092-A_2397636.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":2289,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T06:00:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"039078-008-A_fr","programId":"039078-008-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/039078-008-A/les-aventures-culinaires-de-sarah-wiener/","title":"Les aventures culinaires de Sarah Wiener","subtitle":"Aubergines aux petits oignons - Calabre","shortDescription":"En Calabre, sur la côte des Dieux, Sarah apprend le tressage des oignons et les secrets du stockfisch.","fullDescription":"La partie la plus paradisiaque de la Calabre se nomme la côte des Dieux. C'est là que Sarah Wiener fait la connaissance de Tiziana Primozich, ambassadrice de la cuisine calabraise.","images":{"landscape":{"caption":"Sarah et Michele Marotta sur la terrasse d’ »Il Porticello ». ","resolutions":[{"url":"https://static-cdn.arte.tv/resize/17H7tMIouKxCM4TBh7eu7Hy6j9I=/200x113/smart/filters:strip_icc()/apios/Img_data/11/039078-008_swienerkalabrien_01.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/o5NhTbAJ1nkvVgpso3F4-LnQPAA=/400x225/smart/filters:strip_icc()/apios/Img_data/11/039078-008_swienerkalabrien_01.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/e2LI3RygxHHk9gy4-nAbVePbUBQ=/620x350/smart/filters:strip_icc()/apios/Img_data/11/039078-008_swienerkalabrien_01.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/sf0HTGyfF87UabU5mHTLBVN2ZEs=/720x406/smart/filters:strip_icc()/apios/Img_data/11/039078-008_swienerkalabrien_01.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/BHP9VIXI7-sxbcpUwh_qFThoV2w=/940x530/smart/filters:strip_icc()/apios/Img_data/11/039078-008_swienerkalabrien_01.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/zrj_Gn7BkYY9s0o-h6EoWanlUuE=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/11/039078-008_swienerkalabrien_01.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":2592,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T06:40:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"079401-000-A_fr","programId":"079401-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/079401-000-A/les-sept-vies-d-elvis/","title":"Les sept vies d'Elvis","subtitle":null,"shortDescription":"Le \"King\" raconté par ses plus proches collaborateurs artistiques et par ceux qui l'ont côtoyé directement.","fullDescription":"Le \"King\", icône absolue des débuts du rock'n'roll et de pop culture naissante, est raconté par ses plus proches collaborateurs artistiques et par ceux qui l'ont côtoyé directement.","images":{"landscape":{"caption":"Elvis Presley","resolutions":[{"url":"https://static-cdn.arte.tv/resize/-p_6jJZhXt2jcUV81yopKpQ1EWI=/200x113/smart/filters:strip_icc()/apios/Img_data/13/079401-000-A_2438401.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/lhWDKn_tjjdMGc-eA2hwU49HTCI=/400x225/smart/filters:strip_icc()/apios/Img_data/13/079401-000-A_2438401.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/K4y9dEq-nXmN59_o3Cdx_zzxK5A=/620x350/smart/filters:strip_icc()/apios/Img_data/13/079401-000-A_2438401.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/r8YORjpE52Q9FN3bEtHTuB7_O2E=/720x406/smart/filters:strip_icc()/apios/Img_data/13/079401-000-A_2438401.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/fQTB508lPVq2WO2AYjB7WSR5hrI=/940x530/smart/filters:strip_icc()/apios/Img_data/13/079401-000-A_2438401.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/bNxbQXl9MrAdTT3h461w1-Q8cgM=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/13/079401-000-A_2438401.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":5382,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T07:25:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"047919-001-A_fr","programId":"047919-001-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/047919-001-A/contes-des-mers/","title":"Contes des mers","subtitle":"Alaska, la baie des glaciers","shortDescription":"La femme pilote Gayle Ranney, 72 ans, survole depuis 40 ans en hydravion une immense baie en Alaska.","fullDescription":"À travers le monde, certains ont décidé de vivre pour et par l'eau. Retour sur ces populations qui vivent au bord de l'onde. Dans ce volet, nous suivons Gayle Ranney, 72 ans, qui pilote depuis une quarantaine d'années un hydravion et relie les localités inaccessibles d'une immense baie du sud de l'Alaska.","images":{"landscape":{"caption":"La côte de la baie du Prince-William dans le sud de l’Alaska s’étend sur une longueur de 5000 kilomètres. ","resolutions":[{"url":"https://static-cdn.arte.tv/resize/m-GiEa0OFJPZTjSpISYkLFrpD48=/200x113/smart/filters:strip_icc()/apios/Img_data/4/047919-001_mtvalaska_02.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/7BO4Qkkbyiv4Ln-r8pP9xPlm3cI=/400x225/smart/filters:strip_icc()/apios/Img_data/4/047919-001_mtvalaska_02.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/JtExCGoPhhCDfyL5UudFR8lRyoA=/620x350/smart/filters:strip_icc()/apios/Img_data/4/047919-001_mtvalaska_02.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/-xET_lUaWR2QXR1bbGKbNstYHG4=/720x406/smart/filters:strip_icc()/apios/Img_data/4/047919-001_mtvalaska_02.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/h0QoVuJ0yacAV9W4k5M_R-tgz-8=/940x530/smart/filters:strip_icc()/apios/Img_data/4/047919-001_mtvalaska_02.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/GwR7jBjKVsTqjuNevC3SXCb7Lp4=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/4/047919-001_mtvalaska_02.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":2631,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T09:10:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"077318-000-F_fr","programId":"077318-000-F","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/077318-000-F/lumiere-sous-l-arctique/","title":"Lumière sous l'Arctique","subtitle":null,"shortDescription":"Un périple lumineux dans les eaux arctiques, dans le sillage d’une famille d’explorateurs...","fullDescription":"Un périple lumineux dans les eaux arctiques, dans le sillage d’une famille d’explorateurs en quête des premières espèces fluorescentes du monde polaire.","images":{"landscape":{"caption":"Pris dans les glaces, sans possibilite pour le bateau d'avancer et de continuer sa route, l'equipe organise une plongee d exploration de la face cachee de la banquise du passage du nord ouest. CANADA. - \"Under The Pole III\" se trouve en plein milieu du technique passage du Nord Ouest a travers une glace de plus en plus epaisse. Quittant Resolute, la destination suivante est maintenant Gjoa Haven. Une navigation très compliquee s'annonce.","resolutions":[{"url":"https://static-cdn.arte.tv/resize/xbozL9sWSAjoj5pYGsTDKHS_8HM=/200x113/smart/filters:strip_icc()/apios/Img_data/27/077318-000-F_2425913.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/jn0X4MDwMrJe3XBI9ao30PiDwyM=/400x225/smart/filters:strip_icc()/apios/Img_data/27/077318-000-F_2425913.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/vSmq4cRZpvF3LsZ5k7mP8rLxVWE=/620x350/smart/filters:strip_icc()/apios/Img_data/27/077318-000-F_2425913.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/PnDOsIKvuyNWbBQpvTz-iNMQ-ts=/720x406/smart/filters:strip_icc()/apios/Img_data/27/077318-000-F_2425913.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/qzrKreCQKPvLtrB5SN08Tyj2c9E=/940x530/smart/filters:strip_icc()/apios/Img_data/27/077318-000-F_2425913.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/cmvO8r6A46bQoGB4a4XBcAuorm0=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/27/077318-000-F_2425913.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3145,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T09:55:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"079054-163-A_fr","programId":"079054-163-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/079054-163-A/arte-journal/","title":"ARTE Journal","subtitle":null,"shortDescription":"L'édition de la mi-journée du JT d'ARTE.","fullDescription":"La rédaction franco-allemande d'ARTE Journal pose son regard original sur le monde et propose une approche européenne et culturelle de l’actualité.","images":{"landscape":{"caption":"ARTE Journal","resolutions":[{"url":"https://static-cdn.arte.tv/resize/nMGTY73s-GWVfx8k56ORHeiVIzo=/200x113/smart/filters:strip_icc()/apios/Img_data/27/079054-163-A_2492050.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/PtYOiLNwGugAIxN-eOC0ZYq1e4g=/400x225/smart/filters:strip_icc()/apios/Img_data/27/079054-163-A_2492050.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/DE8-21nER5jBXR4IpafxW4XFpLA=/620x350/smart/filters:strip_icc()/apios/Img_data/27/079054-163-A_2492050.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/P1itk297BUFQN6RF8Kv7RCExf2I=/720x406/smart/filters:strip_icc()/apios/Img_data/27/079054-163-A_2492050.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/VzR0rtw_SP_GPobLfGtkhVjzm2o=/940x530/smart/filters:strip_icc()/apios/Img_data/27/079054-163-A_2492050.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/3bMmffHG9khOz_L1Knr73ruEFcY=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/27/079054-163-A_2492050.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":840,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T10:50:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"078229-003-A_fr","programId":"078229-003-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/078229-003-A/arte-regards/","title":"ARTE Regards","subtitle":"Un bac en Turquie","shortDescription":"Le lycée allemand d’Istanbul a-t-il encore un avenir ?","fullDescription":"Cette année, le jeune Berkin Ersoy passe son abitur, l'équivalent allemand du baccalauréat. Il fait partie des quelques élèves turcs à avoir intégré le lycée privé allemand d’Istanbul – un établissement réputé qui permet aux lycéens de poursuivre leurs études en Allemagne – qui fête aujourd’hui ses 150 ans.","images":{"landscape":{"caption":"Un bac en Turquie ","resolutions":[{"url":"https://static-cdn.arte.tv/resize/SSR_gTAZtRqLGMOHEzHmqX4yQks=/200x113/smart/filters:strip_icc()/apios/Img_data/5/078229-003-A_2480776.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/f1Mo15VdGQ5Bh0eCI_JbCLQCD54=/400x225/smart/filters:strip_icc()/apios/Img_data/5/078229-003-A_2480776.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/2srbZOosVgK09KMybQGnRVcSP3w=/620x350/smart/filters:strip_icc()/apios/Img_data/5/078229-003-A_2480776.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/cfXn0dLQVWqo50KzZh2BVqlFynA=/720x406/smart/filters:strip_icc()/apios/Img_data/5/078229-003-A_2480776.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/J0NFVw4uW-UV73zaWKmgtvfDwFU=/940x530/smart/filters:strip_icc()/apios/Img_data/5/078229-003-A_2480776.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/G_KAeyK7fuwgzje15r35a8Fz54w=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/5/078229-003-A_2480776.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":1821,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T11:00:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"035698-000-A_fr","programId":"035698-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/035698-000-A/les-aventuriers/","title":"Les aventuriers","subtitle":null,"shortDescription":"Un film fétiche qui célèbre le rêve et l’aventure virile, avec Alain Delon et Lino Ventura dans les eaux africaines.","fullDescription":"Unis par une indéfectible amitié et un goût prononcé pour les aventures extrêmes, Roland et Manu apprennent qu'un trésor dort au large des côtes du Congo, à la suite du crash d'un avion... Un film qui célèbre le rêve et l'aventure virile, avec Alain Delon et Lino Ventura au sommet de leur art.","images":{"landscape":{"caption":"Alain Delon et Lino Ventura","resolutions":[{"url":"https://static-cdn.arte.tv/resize/UaF8f2iLxFUv8nBmP4B-KfNgOxU=/200x113/smart/filters:strip_icc()/apios/Img_data/28/035698-000-A_2457018.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/yjviyoRCRnDg8xL3m9au_K5q7k8=/400x225/smart/filters:strip_icc()/apios/Img_data/28/035698-000-A_2457018.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/zWjEWRUVSujcBCROph51ztgAD7I=/620x350/smart/filters:strip_icc()/apios/Img_data/28/035698-000-A_2457018.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/PGjA-DF9wPjuQvLgLxqYK0GVpCc=/720x406/smart/filters:strip_icc()/apios/Img_data/28/035698-000-A_2457018.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/5MzblyJ5DBAXfjLCoWJkfghWekw=/940x530/smart/filters:strip_icc()/apios/Img_data/28/035698-000-A_2457018.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/pnacrtFf7T5nWxMucUtvhzrJHSk=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/28/035698-000-A_2457018.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":6529,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T11:35:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"049266-000-A_fr","programId":"049266-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/049266-000-A/ethiopie-entre-tradition-et-modernite/","title":"Ethiopie, entre tradition et modernité","subtitle":null,"shortDescription":"Fuyant un mariage arrangé, Roba s'exile à Addis-Abeba pour réaliser son rêve : entrer à l'université.","fullDescription":"Roba était gardien de bétail dans un petit village d'Éthiopie. Mais lorsque sa famille a voulu le contraindre à un mariage arrangé, il a préféré l'exil. Prenant le chemin de la capitale, Addis-Abeba, il est parvenu à y réaliser son rêve : entrer à l'université. Ce documentaire met en lumière un pays traversé de contradictions.","images":{"landscape":{"caption":"A l’occasion du mariage de son frère, Roba retourne à son village natal. ","resolutions":[{"url":"https://static-cdn.arte.tv/resize/1Vx8tte5ERsbTuW-r5QhATVzpuo=/200x113/smart/filters:strip_icc()/apios/Img_data/5/049266-000_aethiopien_01.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/BxoCy6U70UYJ5opEfekiSE7Ww4M=/400x225/smart/filters:strip_icc()/apios/Img_data/5/049266-000_aethiopien_01.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/1q1pz58V3sCVx6xHIaXJfEotRsg=/620x350/smart/filters:strip_icc()/apios/Img_data/5/049266-000_aethiopien_01.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/o7F69x2YUbsYqF0PPcnbokMNJdc=/720x406/smart/filters:strip_icc()/apios/Img_data/5/049266-000_aethiopien_01.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/x286graJDY5k4uokpagBYHg-iFY=/940x530/smart/filters:strip_icc()/apios/Img_data/5/049266-000_aethiopien_01.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/v6ApJQ6xlzd2WJafuxGmjEncxLE=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/5/049266-000_aethiopien_01.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3108,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T13:40:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"078727-028-A_fr","programId":"078727-028-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/078727-028-A/invitation-au-voyage/","title":"Invitation au voyage","subtitle":"Le Rhin d’Apollinaire / Porto / La Grande Mosquée de Paris","shortDescription":"Le Rhin, la rencontre poétique d’Apollinaire - L’âme baroque de Porto - La Grande Mosquée de Paris","fullDescription":"Linda Lorin nous emmène à la découverte de trois lieux de notre patrimoine artistique, culturel et naturel. Dans ce numéro : Le Rhin, la rencontre poétique d’Apollinaire - L’âme baroque de Porto - L’incontournable : la Grande Mosquée de Paris.","images":{"landscape":{"caption":"Le Rhin, ce fleuve aux courbes sinueuses traverse l'Allemagne après avoir longé la France, pour aller se jeter dans la Mer du nord. Son flux parcourt des paysages changeants, ici des plaines où s'élèvent des villes, là, des vallées étroites à la nature préservée, parsemées de châteaux et de villages médiévaux. C?est ici qu?Apollinaire forge son univers poétique. Il fait éclore au détour du Rhin quelques-uns de ses plus grands chefs-d'?uvre.","resolutions":[{"url":"https://static-cdn.arte.tv/resize/0EKsEQFepfEn7nk0RKQVG1wEo60=/200x113/smart/filters:strip_icc()/apios/Img_data/10/078727-028-A_2279225.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/lwEHIRQ3dYWq-YIchzT_g8QYLJw=/400x225/smart/filters:strip_icc()/apios/Img_data/10/078727-028-A_2279225.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/jsOz9Rsb7nhEZ-LRJAyl2bmGy9I=/620x350/smart/filters:strip_icc()/apios/Img_data/10/078727-028-A_2279225.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/7qsx_jndFw8gyQHL8RAjradzeAo=/720x406/smart/filters:strip_icc()/apios/Img_data/10/078727-028-A_2279225.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/sboOCP0BekGgPBLVJDTsC1OCtUs=/940x530/smart/filters:strip_icc()/apios/Img_data/10/078727-028-A_2279225.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/dcw_Zxse5CEOXIj71aFnRoUdn2g=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/10/078727-028-A_2279225.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":2273,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T14:30:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"070803-004-A_fr","programId":"070803-004-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/070803-004-A/xenius/","title":"Xenius","subtitle":"Comment faire face à la mort ?","shortDescription":"La mort, un sujet tabou ? Fin de vie, mort biologique, funérarium : comment en parler aux enfants ?","fullDescription":"Dans nos sociétés contemporaines, la mort est un sujet tabou. Est-il utile de connaître la dimension biologique de ce processus ? De quelle façon en parler aux enfants ? Les présentateurs de \"Xenius\" assistent à un séminaire entre étudiants en médecine et patients en fin de vie, avant de se rendre dans un funérarium de Munich où l'on accompagne ceux qui ont perdu un proche.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/up_KTklI7JlUBrT82Baj1GHBgcc=/200x113/smart/filters:strip_icc()/apios/Img_data/22/070803-004-A_2028549.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/d29so7IRob5zu-5ATaMEdLdpldg=/400x225/smart/filters:strip_icc()/apios/Img_data/22/070803-004-A_2028549.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/fOBxQx3PEWMGSpG89BfrMHM9aPw=/620x350/smart/filters:strip_icc()/apios/Img_data/22/070803-004-A_2028549.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/mDW12p9oYgF4F5yS8ySog1rRQak=/720x406/smart/filters:strip_icc()/apios/Img_data/22/070803-004-A_2028549.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/0YuccHrkH5S-j3GrjZZPDFI7JF8=/940x530/smart/filters:strip_icc()/apios/Img_data/22/070803-004-A_2028549.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/pVQcCoVsKN4f0DaTaTmN4qMEVdw=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/22/070803-004-A_2028549.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":1548,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T15:10:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"047285-013-A_fr","programId":"047285-013-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/047285-013-A/paysages-d-ici-et-d-ailleurs/","title":"Paysages d'ici et d'ailleurs","subtitle":"Val de Loire","shortDescription":"Inscrit au patrimoine mondial de l’Unesco, le Val de Loire déroule sur plus de 280 kilomètres son paysage exceptionnel.","fullDescription":"Au XIIe siècle, les moines de Saumur ont lancé la construction d'une digue longue de quarante-cinq kilomètres afin de préserver les cultures des caprices de la Loire. L'homme a dû extraire d'importantes quantités de sable et de gravier qui ont conduit à l'enfoncement du lit du fleuve, menaçant les écosystèmes.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/gg8NIl3KxRFXD0o_GRzyaQiusRc=/200x113/smart/filters:strip_icc()/apios/Img_data/29/047285-013_wdl-valloire_02.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/OpDRWog5GwtdKuaPEjsgNAELmmg=/400x225/smart/filters:strip_icc()/apios/Img_data/29/047285-013_wdl-valloire_02.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/u-xziZR0dLeXfLhPMtF0fOkjgDI=/620x350/smart/filters:strip_icc()/apios/Img_data/29/047285-013_wdl-valloire_02.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/3ORhsvyH6nfCYMqyPXNEQTcSg1U=/720x406/smart/filters:strip_icc()/apios/Img_data/29/047285-013_wdl-valloire_02.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/Fxfs0H9Wi-nl1flk0Gi3WzvLzMg=/940x530/smart/filters:strip_icc()/apios/Img_data/29/047285-013_wdl-valloire_02.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/JdRwarjL6wRqWU8hIhKXUJmSqiU=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/29/047285-013_wdl-valloire_02.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":1550,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T15:35:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"047362-008-A_fr","programId":"047362-008-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/047362-008-A/douces-france-s/","title":"Douces France(s)","subtitle":"En Corse","shortDescription":"La Corse, cette \"montagne dans la mer\" qui a inspiré tant d'artistes, s’éveille aujourd'hui au tourisme vert.","fullDescription":"Un panorama des plus belles régions de France, en compagnie de ceux qui y vivent. Dans cet épisode : découverte fantastique de la Corse : falaises empourprées qui plongent à pic dans la mer, villages accrochés à la montagne, gorges taillées dans la pierre, collines tapissées de châtaigniers ou d’oliviers.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/eQ1uZ7L_maHjDmj-DTEAIYFkP7A=/200x113/smart/filters:strip_icc()/apios/Img_data/11/047362-008_bf-korsika_03.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/W5F-p7UuGUlZ2YnC7LhyrS4yERY=/400x225/smart/filters:strip_icc()/apios/Img_data/11/047362-008_bf-korsika_03.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/Xu_d6b6ZLgSzS0WI2h_fnTi2KhU=/620x350/smart/filters:strip_icc()/apios/Img_data/11/047362-008_bf-korsika_03.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/m8BUPGQsjbtAChoOWBF3jkKeokg=/720x406/smart/filters:strip_icc()/apios/Img_data/11/047362-008_bf-korsika_03.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/AtdZbd-enDZ98Ib2nGBv3gUuBpo=/940x530/smart/filters:strip_icc()/apios/Img_data/11/047362-008_bf-korsika_03.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/OGzZVxVHDhD-4goJhNp_FTbJoss=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/11/047362-008_bf-korsika_03.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3119,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T16:05:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"065296-000-A_fr","programId":"065296-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/065296-000-A/girafes-les-dernieres-geantes/","title":"Girafes, les dernières géantes","subtitle":null,"shortDescription":"Du grand saut à la naissance au contrôle de leur tension : les girafes, une espèce mystérieuse mais menacée.","fullDescription":"Comment les girafons peuvent-ils faire un saut de 1,80 mètre à la naissance ? Comment les girafes parviennent-elles à parfaitement contrôler leur tension sanguine, au point que les astronautes s'en inspirent ? Une exploration du monde complexe et mystérieux des girafes, espèce aujourd'hui menacée.","images":{"landscape":{"caption":"Deux girafes réticulées nez-à-nez, dans la réserve nationale de Samburu, au Kenya.","resolutions":[{"url":"https://static-cdn.arte.tv/resize/cvQkj1WR8hDAFjKvZ3dRoqurQlI=/200x113/smart/filters:strip_icc()/apios/Img_data/5/065296-000-A_1799803.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/2RKDnoKpslihZZ-kCLqJKxIbVEY=/400x225/smart/filters:strip_icc()/apios/Img_data/5/065296-000-A_1799803.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/RPGzcPGhtZJgGSlwkkNGlm2W0Gc=/620x350/smart/filters:strip_icc()/apios/Img_data/5/065296-000-A_1799803.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/1HylKglgYwiiIo7Ugp4VbvCWBJY=/720x406/smart/filters:strip_icc()/apios/Img_data/5/065296-000-A_1799803.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/IzwPEjRmoynLPBmCU32r1YSdpqU=/940x530/smart/filters:strip_icc()/apios/Img_data/5/065296-000-A_1799803.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/n-rDBR1WDL9X8Y-jy7WyLaINI50=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/5/065296-000-A_1799803.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":2583,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T17:00:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"079056-163-A_fr","programId":"079056-163-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/079056-163-A/arte-journal/","title":"ARTE Journal","subtitle":null,"shortDescription":"L'édition du soir d'ARTE Journal.","fullDescription":"Chaque jour à 19h45, la rédaction franco-allemande d'ARTE Journal propose une approche européenne et culturelle de l'actualité. Un regard original sur le monde.","images":{"landscape":{"caption":"ARTE Journal","resolutions":[{"url":"https://static-cdn.arte.tv/resize/FwsyeAilMOwOlsKn1OTHSPIvZLc=/200x113/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/MRFleo30rTQD1lcyLtAiEMuU1dc=/400x225/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/KiceRb0h8Il0Jh1cGLbUXBsvKpo=/620x350/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/ctvesLfMV1rYLoUn52DiKsuaz7g=/720x406/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/6Wi-qpgrxzwEIUIL2wFQU2E-AaY=/940x530/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/CJPIGAZKAcVP-39p7jUcDUf_7Nw=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":1500,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T17:45:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"081596-033-A_fr","programId":"081596-033-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/081596-033-A/28-minutes/","title":"28 Minutes","subtitle":"Émission spéciale internationale avec In Koli Jean Bofane (15/08/2018)","shortDescription":"L'écrivain In Koli Jean Bofane est l’invité grand témoin de 28’. Découvrez son portrait par Amira Souilem.\n\n \n ","fullDescription":"L’écrivain In Koli Jean Bofane dénonce la précarité des migrants et la corruption dans son roman \"La Belle de Casa\". Avec le journaliste britannique Philip Turle et la journaliste italienne et fondatrice du site d’information Da Vinci Post Eva Morletto, il reviendra sur deux sujets d’actualités : \"Turquie : Trump veut-il la peau d'Erdogan ?\" et \"Monsanto : le jugement historique\".","images":{"landscape":{"caption":"Émission spéciale internationale avec In Koli Jean Bofane","resolutions":[{"url":"https://static-cdn.arte.tv/resize/yI2e270s7TLB4BYmb7PSZJMLddI=/200x113/smart/filters:strip_icc()/apios/Img_data/8/081596-033-A_2494338.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/27HEOSojbsVRwc5EU4gQEr7SjDg=/400x225/smart/filters:strip_icc()/apios/Img_data/8/081596-033-A_2494338.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/H7eLnCLEpSgvP1RDoTYiHRdR3Ys=/620x350/smart/filters:strip_icc()/apios/Img_data/8/081596-033-A_2494338.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/OXkRzIKcI9xTUYHh9j5HsTvpDVg=/720x406/smart/filters:strip_icc()/apios/Img_data/8/081596-033-A_2494338.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/Hh-TMKOOVNsVG7Be7Rs61sY2lNo=/940x530/smart/filters:strip_icc()/apios/Img_data/8/081596-033-A_2494338.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/xD0jTqRFFeHKSZI1p6Byj7EaXB4=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/8/081596-033-A_2494338.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":3600,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T18:05:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"051462-022-A_fr","programId":"051462-022-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/051462-022-A/la-minute-vieille/","title":"La minute vieille","subtitle":"Secret professionnel","shortDescription":"Un secret professionnel : comment décupler son chiffre d’affaires avec un remède de grand-mère ?","fullDescription":"Les mamies grivoises n'ont pas pris une ride ! Une quatrième saison ponctuée des apparitions des guests Michel Galabru, Claude Brasseur et Michel Robin. Aujourd'hui, un secret professionnel : comment décupler son chiffre d’affaires avec un remède de grand-mère ?","images":{"landscape":{"caption":"Secret professionnel","resolutions":[{"url":"https://static-cdn.arte.tv/resize/ZFHKJ5c0ZU9PfJhzV1AhRZemGRg=/200x113/smart/filters:strip_icc()/apios/Img_data/19/051462-022-A_1805643.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/eZASQMA52l0O6kAkdj1t_LapAbY=/400x225/smart/filters:strip_icc()/apios/Img_data/19/051462-022-A_1805643.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/k7NLtdQ-q-YFuRdHOm6b8cnGvHs=/620x350/smart/filters:strip_icc()/apios/Img_data/19/051462-022-A_1805643.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/gHm9c-giVZxJlp7Gcut9L2iDeAw=/720x406/smart/filters:strip_icc()/apios/Img_data/19/051462-022-A_1805643.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/eSjuD1ERABGzz7lS3JSexuOulbI=/940x530/smart/filters:strip_icc()/apios/Img_data/19/051462-022-A_1805643.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/p7WVWGnq_E3JH6iA4NelwRLIvVs=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/19/051462-022-A_1805643.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":120,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T18:51:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"047384-000-A_fr","programId":"047384-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/047384-000-A/diabolo-menthe/","title":"Diabolo menthe","subtitle":null,"shortDescription":"Premier film (et premier coup d'éclat) pour Diane Kurys, qui signe une chronique subtile de l'adolescence.","fullDescription":"Au début des années 1960, deux soeurs font l'apprentissage de la vie, de l'amour, de la politique... Premier film (et premier coup d'éclat) pour Diane Kurys, qui signe avec \"Diabolo menthe\" une chronique subtile de l'adolescence.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/7Iq7npyOFwQadsZUmexB_tW1EUA=/200x113/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/S9IJ45UqJAwMFfinjBDiRK45CuE=/400x225/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/1Kq_vSqDL3l5KM7Mn4BWHVYTUqM=/620x350/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/EjkiKvpomolNpaZCo_6h_Yfa7Vo=/720x406/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/xfEFVcoRIT1ubGn48ELyR8dtubk=/940x530/smart/filters:strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/74HUDjNSBe7U6jzhPO-73py8Rr8=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/15/047384-000_kleineparis_04m.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":5714,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T18:55:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"048641-006-A_fr","programId":"048641-006-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/048641-006-A/jesus-et-l-islam-4-7/","title":"Jésus et l’islam (4/7)","subtitle":"L’exil du Prophète","shortDescription":"Pourquoi l'exil de Mahomet de La Mecque à Médine (l’hégire) fonde-t-il l’ère musulmane ?","fullDescription":"Pourquoi Jésus occupe-t-il une place exceptionnelle dans le Coran ? Enquête sur les origines et la genèse de l’islam. Quatrième volet : pourquoi l'exil de Mahomet de La Mecque à Médine (l’hégire) fonde-t-il l’ère musulmane ? Permet-il d’opérer la distinction entre les sourates mecquoises et les sourates médinoises ? Peut-on reconstituer la chronologie du Coran ?","images":{"landscape":{"caption":"L'EXIL DU PROPHETE","resolutions":[{"url":"https://static-cdn.arte.tv/resize/fkrTwdsy29GcNEcjHDNWM6MJNAE=/200x113/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/g3eTyTo_b1QZza9Huv-dzxckLGw=/400x225/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/bqjk8wgFfY9Y770uRipcPlzcj9c=/620x350/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/wGTJkDzcDPrdXcf1XnJe0bV7Tvw=/720x406/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/fZU2S2Nm5Z67fC19WnTCU6R4KWI=/940x530/smart/filters:strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/g9DDe0c0_ZCo4z5AQKYEfsZN99E=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/27/048641-006-A_2484451.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":3134,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T20:30:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"048641-007-A_fr","programId":"048641-007-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/048641-007-A/jesus-et-l-islam-5-7/","title":"Jésus et l’islam (5/7)","subtitle":"Mahomet et la Bible","shortDescription":"Pourquoi le Coran fait-il référence à la Bible hébraïque et aux textes chrétiens, notamment les apocryphes ?","fullDescription":"Pourquoi Jésus occupe-t-il une place exceptionnelle dans le Coran ? Les auteurs de \"Corpus Christi\" enquêtent sur les origines et la genèse de l’islam auprès de vingt-six chercheurs du monde entier. Cinquième volet : le Coran fait de nombreuses références à la Bible hébraïque et aux textes chrétiens, notamment les évangiles apocryphes. D’où Mahomet tirait-il ce savoir ?","images":{"landscape":{"caption":"JESUS ET L'ISLAM // MAHOMET ET LA BIBLE","resolutions":[{"url":"https://static-cdn.arte.tv/resize/881xX81-YzphEFeQR-GXOUx2YkQ=/200x113/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/GRg9MP3bzbfpbxaY0aqDBK-juGc=/400x225/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/5aX1lTyHbfy2cUDEUv20B7dflZQ=/620x350/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/zxqB-pC_n__9a-9UGKqlEwTfrcY=/720x406/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/bi7s99mrkYn76rimxvEuWfBvmWQ=/940x530/smart/filters:strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/7ONeCXQUIRq6sHE-VrOK4-K26PI=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/11/048641-007-A_2491889.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":3159,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T21:25:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"061703-000-A_fr","programId":"061703-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/061703-000-A/peut-on-outrager-dieu/","title":"Peut-on outrager Dieu ?","subtitle":"La question du blasphème","shortDescription":"L'histoire ancienne et contemporaine du blasphème dans l'art et de ses conséquences pour les auteurs.","fullDescription":"Liberté d'expression pour certains, critique des religions pour d'autres, la question du blasphème déchaîne aujourd'hui les passions. Illustration à travers des exemples artistiques récents.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/earJ8_Ti-aflLa2kwow2iln9umg=/200x113/smart/filters:strip_icc()/apios/Img_data/9/061703-000-A_1846111.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/1DrZH7S1jkeauCOUxCLxRaAS7nk=/400x225/smart/filters:strip_icc()/apios/Img_data/9/061703-000-A_1846111.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/yApJWgsg0Zj0BpfRREK9tSSZ8vA=/620x350/smart/filters:strip_icc()/apios/Img_data/9/061703-000-A_1846111.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/v2E7S_SGEsraF1WFnEs-1FguVkg=/720x406/smart/filters:strip_icc()/apios/Img_data/9/061703-000-A_1846111.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/j0bU8AD4g0i-QrLyuKmNWXyIUzU=/940x530/smart/filters:strip_icc()/apios/Img_data/9/061703-000-A_1846111.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/ruoKf-XmeJj0XkD90YHN_UwjRRs=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/9/061703-000-A_1846111.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":3114,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T22:20:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"046739-000-A_fr","programId":"046739-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/046739-000-A/de-l-autre-cote-du-mur/","title":"De l’autre côté du mur","subtitle":null,"shortDescription":"Passée à l'Ouest, Nelly est soupçonnée par la CIA d'être une espionne à la solde de l'Allemagne de l'Est.","fullDescription":"Une mère de famille de la RDA passe à l'Ouest. Mais entre suspicion, interrogatoires et mystères, le rêve d'une vie plus libre va devoir attendre... Pour son interprétation magistrale de Nelly Senff, Jördis Triebel s'est vue décerner plusieurs récompenses prestigieuses.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/0Lr0D8cpBQfeEw8dvVmO3wxgTVk=/200x113/smart/filters:strip_icc()/apios/Img_data/7/046739-000-A_1774199.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/iMw7zliHvqUTiQ7y86D-VCsbfuI=/400x225/smart/filters:strip_icc()/apios/Img_data/7/046739-000-A_1774199.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/praYLSkGl_6vo4uMBDQBtawphnk=/620x350/smart/filters:strip_icc()/apios/Img_data/7/046739-000-A_1774199.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/uZq1jaodTAGeheaP4NTVcgnjrzw=/720x406/smart/filters:strip_icc()/apios/Img_data/7/046739-000-A_1774199.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/jMwSdZxuCL87xJ2a7TW_gqwRa18=/940x530/smart/filters:strip_icc()/apios/Img_data/7/046739-000-A_1774199.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/pvoyaJCYJD-WHotR5HxeivVOML0=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/7/046739-000-A_1774199.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":5584,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-15T23:15:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"048169-000-A_fr","programId":"048169-000-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/048169-000-A/celui-qui-a-deux-ames/","title":"Celui qui a deux âmes","subtitle":null,"shortDescription":"Dans le grand Nord, un conte Inuit sur un homme aux deux sensibilités, féminine et masculine...","fullDescription":"Dans le grand Nord, un conte inuit sur un homme aux deux sensibilités, féminine et masculine... Ce court métrage a été couronné par le Prix du meilleur court métrage d'animation au Flickerfest 2016.","images":{"landscape":{"caption":null,"resolutions":[{"url":"https://static-cdn.arte.tv/resize/l_0mIsJYMm020jlpYTyewqi3SEU=/200x113/smart/filters:strip_icc()/apios/Img_data/2/048169-000-A_zwei-seelen_01.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/R2XqBCeHw9bejwgmmCSz25M0r9M=/400x225/smart/filters:strip_icc()/apios/Img_data/2/048169-000-A_zwei-seelen_01.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/qvaTqSsuxvyOFzcW_3TqAl7K5s0=/620x350/smart/filters:strip_icc()/apios/Img_data/2/048169-000-A_zwei-seelen_01.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/pI8O0Th_pKl0ir7vzufvmrMLaD8=/720x406/smart/filters:strip_icc()/apios/Img_data/2/048169-000-A_zwei-seelen_01.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/nzRB3twE58aWXUDGECtHJkx24Ts=/940x530/smart/filters:strip_icc()/apios/Img_data/2/048169-000-A_zwei-seelen_01.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/vgp2RQUu2QYA7MXeXwhs0Owz8ZE=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/2/048169-000-A_zwei-seelen_01.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":994,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-16T00:45:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"079056-163-A_fr","programId":"079056-163-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/079056-163-A/arte-journal/","title":"ARTE Journal","subtitle":null,"shortDescription":"L'édition du soir d'ARTE Journal.","fullDescription":"Chaque jour à 19h45, la rédaction franco-allemande d'ARTE Journal propose une approche européenne et culturelle de l'actualité. Un regard original sur le monde.","images":{"landscape":{"caption":"ARTE Journal","resolutions":[{"url":"https://static-cdn.arte.tv/resize/FwsyeAilMOwOlsKn1OTHSPIvZLc=/200x113/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/MRFleo30rTQD1lcyLtAiEMuU1dc=/400x225/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/KiceRb0h8Il0Jh1cGLbUXBsvKpo=/620x350/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/ctvesLfMV1rYLoUn52DiKsuaz7g=/720x406/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/6Wi-qpgrxzwEIUIL2wFQU2E-AaY=/940x530/smart/filters:strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/CJPIGAZKAcVP-39p7jUcDUf_7Nw=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/30/079056-163-A_2492051.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":1500,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-16T01:05:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"053444-012-A_fr","programId":"053444-012-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/053444-012-A/paysages-d-ici-et-d-ailleurs/","title":"Paysages d’ici et d’ailleurs","subtitle":"Spreewald, Allemagne","shortDescription":"Aménagés en canaux au XVIIIe siècle, les marais du Spreewald sont classés réserve de biosphère depuis 1991.","fullDescription":"À quelque 100 km au sud-est de Berlin, entre prairies et forêts, la vie s’organise depuis des siècles autour de la rivière Spree et de ses canaux. Les marais du Spreewald ont été majoritairement aménagés en canaux par Frédéric II au XVIIIe siècle. Le Spreewald est classé réserve de biosphère de l’Unesco depuis 1991.","images":{"landscape":{"caption":"Le jardin fleuri du chef Peter Funke dans le village de Burg","resolutions":[{"url":"https://static-cdn.arte.tv/resize/8RcbxI-16v2OkK3o1-7BkfznWB0=/200x113/smart/filters:strip_icc()/apios/Img_data/12/053444-012-A_wdlsdm-spreewald_01.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/a3jQQJGsgICsmrKYPQ3I3U5GTYk=/400x225/smart/filters:strip_icc()/apios/Img_data/12/053444-012-A_wdlsdm-spreewald_01.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/Fx_DeOu8SagrhH8hHhvaop2BWkQ=/620x350/smart/filters:strip_icc()/apios/Img_data/12/053444-012-A_wdlsdm-spreewald_01.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/SMGPzWunJru08h-SW0j0v57ctt4=/720x406/smart/filters:strip_icc()/apios/Img_data/12/053444-012-A_wdlsdm-spreewald_01.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/HQUGGHyFXxWDAIzCVKppN2o8_Uw=/940x530/smart/filters:strip_icc()/apios/Img_data/12/053444-012-A_wdlsdm-spreewald_01.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/dYzoRBazsgWatYqKZa1UBz38Ymc=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/12/053444-012-A_wdlsdm-spreewald_01.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[],"duration":1560,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-16T01:25:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null},{"id":"079474-028-A_fr","programId":"079474-028-A","type":"program","kind":{"code":"SHOW","label":null},"url":"https://www.arte.tv/fr/videos/079474-028-A/arte-regards/","title":"ARTE Regards","subtitle":"Après la crise, les Grecs face à la corruption","shortDescription":"En Grèce, Kristina Tremonti lutte contre la corruption et la fraude fiscale.\n ","fullDescription":"Kristina Tremonti veut montrer que la Grèce a un avenir : elle a quitté le poste hautement rémunéré qu’elle occupait à New York pour retourner à Athènes, où elle lutte contre la corruption et la fraude fiscale.","images":{"landscape":{"caption":"Kristina Tremonti lutte contre la corruption en Grèce.","resolutions":[{"url":"https://static-cdn.arte.tv/resize/VOulPjP1RKiBQ-weEBHoXrvnbkU=/200x113/smart/filters:strip_icc()/apios/Img_data/18/079474-028-A_2477368.jpg","width":200,"height":113},{"url":"https://static-cdn.arte.tv/resize/PGPp8zIGV95C0Al_TSFiaoDNXCk=/400x225/smart/filters:strip_icc()/apios/Img_data/18/079474-028-A_2477368.jpg","width":400,"height":225},{"url":"https://static-cdn.arte.tv/resize/AJGh7mVVRV8V4S2bIKHoEjPJY00=/620x350/smart/filters:strip_icc()/apios/Img_data/18/079474-028-A_2477368.jpg","width":620,"height":350},{"url":"https://static-cdn.arte.tv/resize/hLEZI_BvA3ZzIacXqHOJ8unxKMo=/720x406/smart/filters:strip_icc()/apios/Img_data/18/079474-028-A_2477368.jpg","width":720,"height":406},{"url":"https://static-cdn.arte.tv/resize/E9fqzFH294Ngw_xjq2-MFvhwWYM=/940x530/smart/filters:strip_icc()/apios/Img_data/18/079474-028-A_2477368.jpg","width":940,"height":530}],"blurUrl":"https://static-cdn.arte.tv/resize/gdEKYPsonu62m3jyDqRAjIZ3gLA=/80x45/smart/filters:quality(80):blur(2):strip_exif():strip_icc()/apios/Img_data/18/079474-028-A_2477368.jpg"},"banner":null,"square":null,"portrait":null},"stickers":[{"code":"PLAYABLE","label":"PLAYABLE"}],"duration":1807,"player":{"html":"","linkIos":null,"linkAndroid":null},"availability":null,"broadcastDates":["2018-08-16T01:55:00Z"],"credits":[],"shopUrl":null,"geoblocking":null,"livestreamRights":null,"partners":null,"offlineAvailability":null}]}]}
\ No newline at end of file
diff --git a/providers/artetv/testdata/info.md b/providers/artetv/testdata/info.md
deleted file mode 100644
index 558e7ca..0000000
--- a/providers/artetv/testdata/info.md
+++ /dev/null
@@ -1,159 +0,0 @@
-# Informations collected so far
-
-by date : YY-MM-DD
-https://www.arte.tv/guide/api/api/pages/fr/TV_GUIDE/?day=18-07-13
---> JSON
-
-
-
-Search query :
-https://www.arte.tv/guide/api/api/zones/fr/listing_SEARCH/?page=1&limit=200&query=cartes
-
-
-Some fact abot IDs
-ID collection / emission : RC-014036
-ID episode 067846-030-A
-
-
-Show's Page
-https://www.arte.tv/fr/videos/RC-014036/le-dessous-des-cartes/
-
-
-Categorie's shows
- /guide/api/api/zones/fr/listing_MAGAZINES/?page=2&limit=20
-
-Subcategories's shows :
-ex Musique POP
-https://www.arte.tv/guide/api/api/zones/fr/videos_subcategory_POP/?page=2&limit=10
-
-
-
-Most viewed:
-https://www.arte.tv/guide/api/api/zones/fr/listing_MOST_VIEWED/?page=2&limit=20
-
-
-
-
-Actualité du cinéma ACC
-https://www.arte.tv/guide/api/api/zones/fr/videos_subcategory_ACC/?page=2&limit=10
-
-
-Séries :
-https://www.arte.tv/guide/api/api/zones/fr/videos_subcategory_SES/?page=1&limit=20
-
-
-https://www.arte.tv/guide/api/api/zones/fr/listing_SEARCH/?page=2&limit=20&query=DC
-
-
-
-Player.js
-https://api.arte.tv/api/player/v1/config/fr/040267-003-A?autostart=1&lifeCycle=1';
-var json_playlis
-
-
-https://api.arte.tv/api/player/v1/config/fr/073071-020-A
-
-
-Postroll: suggestion de vidéo ?
-https://api.arte.tv/api/player/v1/recommendedPostroll/fr/073071-020-A
-Pas toujours...
-
-
-Categories list is in script at https://static-cdn.arte.tv/guide/next.js
-
-In french:
-
-ACT: "Info et société"
- AJO: "ARTE Journal"
- AUV: "Autrement vu"
- KUL: "Actualités culturelles"
- DCY: "Décryptages"
- ENQ: "Enquêtes et reportages"
- JUN: "Junior"
- INFO: "ARTE Info"
-CIN: "Cinéma"
- ACC: "Actualité du cinéma"
- CMG: "Courts métrages"
- FLM: "Films"
- CMU: "Films muets"
- MCL: "Les grands du 7e art"
-SER: "Séries et fictions"
- CHU: "Courts humoristiques"
- FIC: "Fictions"
- SES: "Séries"
-CPO: "Culture et pop"
- ART: "Arts"
- POP: "Culture pop"
- IDE: "Idées"
-ARS: "ARTE Concert"
- ADS: "Arts de la scène"
- CLA: "Classique"
- JAZ: "Jazz"
- MUA: "Musiques actuelles"
- MUD: "Musiques du monde"
- OPE: "Opéra"
-SCI: "Sciences"
- ENB: "En bref"
- ENN: "Environnement et nature"
- SAN: "Médecine et santé"
- TEC: "Technologies et innovations"
-DEC: "Voyages et découvertes"
- ATA: "A table !"
- EVA: "Evasion"
- NEA: "Nature et animaux"
- VIA: "Vies d'ailleurs"
-HIS: "Histoire"
- CIV: "Civilisations"
- LGP: "Les grands personnages"
- XXE: "XXe siècle"
-
-In German:
-ACT: "Aktuelles und Gesellschaft"
- AJO: "ARTE Journal"
- AUV: "Perspektivwechsel"
- KUL: "Kultur News"
- DCY: "Hintergrund"
- ENQ: "Reportagen und Recherchen"
- JUN: "Junior"
- INFO: "ARTE Info"
-CIN: "Kino"
- ACC: "Rund um den Film"
- CMG: "Kurzfilme"
- FLM: "Filme"
- CMU: "Stummfilme"
- MCL: "Filmgrößen"
-SER: "Fernsehfilme und Serien"
- CHU: "Kurz und witzig"
- FIC: "Fernsehfilme"
- SES: "Serien"
-CPO: "Kultur und Pop"
- ART: "Kunst"
- POP: "Popkultur"
- IDE: "Ideenwelten"
-ARS: "ARTE Concert"
- ADS: "Bühnen-Performance"
- CLA: "Klassik"
- JAZ: "Jazz"
- MUA: "Pop"
- MUD: "Weltmusik"
- OPE: "Oper"
-SCI: "Wissenschaft"
- ENB: "Wissen kompakt"
- ENN: "Umwelt und Natur"
- SAN: "Gesundheit und Medizin"
- TEC: "Technik und Innovation"
-DEC: "Entdeckung der Welt"
- ATA: "Kulinarik"
- EVA: "Reisen"
- NEA: "Natur und Tiere"
- VIA: "Leben anderswo"
-HIS: "Geschichte"
- CIV: "Die Zeit vor dem 20. Jahrhundert"
- LGP: "Biographien"
- XXE: "Das 20. Jahrhundert"
-
-
- Collections
- https://www.arte.tv/guide/api/api/zones/fr/collection_videos/?id=RC-014034&page=2
-
-
diff --git a/providers/artetv/testdata/minute.html.txt b/providers/artetv/testdata/minute.html.txt
deleted file mode 100644
index 1d1c512..0000000
--- a/providers/artetv/testdata/minute.html.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
- La minute vieille | ARTE
-
-
-
-
-
-
-
-
-
Les mamies malicieuses sont de retour pour une septième saison bien relevée, avec des guests inattendus. Dans cet épisode : de l’art de découper un saucisson !
Caravane prolétaire, intérieur chic de Méditerranée, maison de campagne fleurie et chalet bigot : depuis leurs quartiers d’été, les mamies à la langue bien pendue reviennent pour une septième salve d’inédits. Aujourd’hui : de l’art de découper un saucisson !