Table of Contents

<texit info> author=Dick Snippe Dick.Snippe@npo.nl title=Vertaal MIDs naar filesysteem paden keywords=mid poms vod backgroundtext= </texit>

Vertaal MIDs naar filesysteem paden

NEP heeft van DDU een lijst met MIDs (POMS id's) gekregen. De data die daarbij hoort wil men graag naar het NEP platform kopieren. De vraag is: hoe vertaal je een lijst aan MIDs naar filesysteem paden? Dit document beschrijft een methode om dat te doen. Als dat nl gedaan is dat kan gebruik gemaakt worden van een ding genaamd “contentslurp.omroep.nl” dat ik eerder opgezet heb om zo al die data op uniforme wijze binnen te krijgen.

Het idee is om dit als een meertrapsraket aan te pakken:

  1. Haal via de POMS api bij elk MID de onderliggende programUrl op
  2. Bepaal aan de hand van hoe die url eruit ziet of je nog meer processing moet doen:
  3. Kies van het lijstje programUrl's degene die je het beste lijkt (hoogste bitrate, h264 > windosmedia, e.d.)
  4. De hoop is dat je uiteindelijk een uniek pad op het filesysteem hebt

Dikke Vette Disclaimer

Langs deze weg wordt content aan NEP ter download aangeboden die anders niet in alle gevallen zomaar downloadbaar is. Voorbeelden hiervan zijn:

Experimenten POMS api

Api downloaden en uitproberen

Ik gebruik jq om JSON te processn, da's gewoon een rpm.

$ sudo dnf install -y jq
$ git clone https://github.com/npo-poms/api
$ cd api/bash
$ cp creds-example.sh creds.sh
$ vi creds.sh
[via Cris heb ik creds voor NEP gekregen]
  apiKey=nepmigratie
  secret=___________________________
  origin=http://dicktest.nepworldwide.nl

Stoeien met jq om nuttige info te verkrijgen

$ ./media/get.sh POW_00722648|jq

 Access-Control-Allow-Headers: accept, authorization, content-type, cookie, origin, x-http-method-override, x-requested-with, x-npo-date, x-npo-mid, x-npo-url,  200, api/media/POW_00722648? @uster=balancer.poms8aas; path=/;, PUT
{
  "objectType": "program",
  "mid": "POW_00722648",
  "type": "BROADCAST",
  "avType": "VIDEO",
  "workflow": "PUBLISHED",
  "sortDate": 1389546000000,
  "creationDate": 1387432091934,
  "lastModified": 1389792202585,
enz...
$ ./media/get.sh RBX_RA4_4628952| jq '.locations[]|.programUrl'
"http://radiobox2.omroep.nl/broadcaststream/file/478896.mp3"

Maar eigenlijk wil ik in 1 klap een lijst aan MIDs kunnen geven.

$ . ./api-functions.sh
get api/media/multiple ids=POW_00470026,POW_00135450|jq

Hoe krijgen we daar de gewenste info uit?

$ get api/media/multiple ids=POW_00470026,POW_00135450|jq '.items[]|.id,(.result|.locations[]|.programUrl)'
"POW_00470026"
"odi+http://odi.omroep.nl/video/h264_sb/POW_00470026"
"odi+http://odi.omroep.nl/video/h264_bb/POW_00470026"
"odi+http://odi.omroep.nl/video/h264_std/POW_00470026"
"odi+http://odi.omroep.nl/video/wvc1_std/POW_00470026"
"odi+http://odi.omroep.nl/video/wmv_sb/POW_00470026"
"odi+http://odi.omroep.nl/video/wmv_bb/POW_00470026"
"POW_00135450"
"http://content.omroep.nl/id/MAX/serie/POW_00135444/POW_00135450/bb.20070921.mp4"
"http://cgi.omroep.nl/cgi-bin/streams?/id/MAX/serie/POW_00135444/POW_00135450/sb.20070921.asf"
"http://cgi.omroep.nl/cgi-bin/streams?/id/MAX/serie/POW_00135444/POW_00135450/bb.20070921.asf"

Met nog een pietsie meer jq-fu zou hier een handig lijstje uit moeten kunnen komen, zou je zeggen.

$ get api/media/multiple ids=POW_00470026,POW_00135450|jq '.items[]|{ id: .id, urls: [ .result|.locations[]|.programUrl ]}'
{
  "id": "POW_00470026",
  "urls": [
    "odi+http://odi.omroep.nl/video/h264_sb/POW_00470026",
    "odi+http://odi.omroep.nl/video/h264_bb/POW_00470026",
    "odi+http://odi.omroep.nl/video/h264_std/POW_00470026",
    "odi+http://odi.omroep.nl/video/wvc1_std/POW_00470026",
    "odi+http://odi.omroep.nl/video/wmv_sb/POW_00470026",
    "odi+http://odi.omroep.nl/video/wmv_bb/POW_00470026"
  ]
}
{
  "id": "POW_00135450",
  "urls": [
    "http://content.omroep.nl/id/MAX/serie/POW_00135444/POW_00135450/bb.20070921.mp4",
    "http://cgi.omroep.nl/cgi-bin/streams?/id/MAX/serie/POW_00135444/POW_00135450/sb.20070921.asf",
    "http://cgi.omroep.nl/cgi-bin/streams?/id/MAX/serie/POW_00135444/POW_00135450/bb.20070921.asf"
  ]
}

Data cleanup

Ik heb van Jantine 10 files gekregen:

VOD cleanup AVROTROS.txt
VOD cleanup BNNVARA.txt
VOD cleanup EO.txt
VOD cleanup HUMAN.txt
VOD cleanup KRO-NCRV.txt
VOD cleanup MAX.txt
VOD cleanup NOS events.txt
VOD cleanup POWNED.txt
VOD cleanup VPRO.txt
VOD cleanup WNL.txt

maar daar zit nog wat rommel in (lege regels, tekstkopjes) Als volgt gecleaned:

$ cat clean.sed
/^[[:blank:]]*$/d
/ /d
/POMS-iD/d
/Titel/d
$ cat *.txt | wc -l
80260
$ sort *.txt | sed -f clean.sed > mids
$ wc -l mids
79893 mids

Wat is dan de rommel die niet meegenomen is?

$ grep -c '^[[:blank:]]*$' *.txt
VOD cleanup AVROTROS.txt:297
VOD cleanup BNNVARA.txt:0
VOD cleanup EO.txt:0
VOD cleanup HUMAN.txt:0
VOD cleanup KRO-NCRV.txt:0
VOD cleanup MAX.txt:42
VOD cleanup NOS events.txt:8
VOD cleanup POWNED.txt:0
VOD cleanup VPRO.txt:1
VOD cleanup WNL.txt:8

$ grep '[[:blank:]]' *.txt
VOD cleanup AVROTROS.txt:AVRO KunstUur
VOD cleanup HUMAN.txt:HUMAN_20050812 vloer
VOD cleanup HUMAN.txt:HUMAN_20050826 vloer
VOD cleanup HUMAN.txt:HUMAN_20050819 vloer
VOD cleanup WNL.txt:De Koning Willem 1 Prijzen  POMS_S_WNL_132698
VOD cleanup WNL.txt:Vrijdag met Vrienden                POMS_S_WNL_133221
VOD cleanup WNL.txt:
VOD cleanup WNL.txt:
VOD cleanup WNL.txt:
VOD cleanup WNL.txt:
VOD cleanup WNL.txt:Wedstrijd van zijn leven    POMS_S_WNL_387871
VOD cleanup WNL.txt:WNL Op Zondag                       POW_03347301

$ grep -E '(POMS-iD|Titel)' *.txt
VOD cleanup AVROTROS.txt:POMS-iD'S
VOD cleanup HUMAN.txt:Titel
VOD cleanup VPRO.txt:POMS-iD

Verder blijken er een hoop duplicaten in te zitten:

$ uniq -d mids|wc -l
1624

Laten we die er nog maar even uitvissen

$ uniq mids >mids.tmp
$ mv mids.tmp mids
$ wc -l mids
79893 mids

Massaal MIDs opvragen

We hebben nu dus een lijst genaamd “mids”. Knip deze in chunks van -zeg- 100 items en vraag die op via api/media/multiple

### dit is mijn workspace waar mijn lijstje mids staat
### en waar ik de rest v/d processing ga doen
$ cd tmp/mid
$ split -l 100 -a 3 -d mids mids.
$ mkdir in
$ mv mids* in

### In ../api staat de git checkout
$ . ../api/bash/api-functions.sh

### ff proberen
$ head -1 in/mids.000
10act0505Canadezen
$ get api/media/multiple ids=10act0505Canadezen | jq
<ziet er goed uit>

$ mkdir out
$ for x in in/mids.???; do echo Doing $x; out=out/${x#in/}; get api/media/multiple ids=$(tr '\n' ',' <$x ) >$out; done

Transmogrificeren

We hebben nu een hele bak met info. Maak daar met jq iets van waar een bash of perl scriptje wat mee zou kunnen. (waarom? Omdat ik in bash beter thuis ben dan in jq. Sorry. Iets met nails en hammers. Hele oude hammers in dit geval.)

$ jq '.items[]|{ id: .id, urls: [ .result|.locations[]|.programUrl ]}' out/mids.??? >data
jq: error (at out/mids.000:0): Cannot iterate over null (null)
...
jq: error (at out/mids.785:0): Cannot iterate over null (null)

De “cannot iterate” errors komen van MIDs die blijkbaar geen programs zijn en geen “.locations.programUrl” hebben. Lekker gecleaned, die data he?

Wat hebben we eigenlijk voor spulletjes er tussen zitten?

 $ jq '.items[]|{ id: .id, type: .result.objectType }' out/mids.???|grep type|sort -u
  "type": "group"
  "type": null
  "type": "program"
  "type": "segment"

Non-program mids

Hierboven hebben we “type: null”. Dat komt van niet bestaande mids. Verder hebben we een type “segment”. Dat kan zo te zien wel gebruikt worden. Daar hangen ook locations aan. Daarnaast hebben we dus ook mids van type “group”. Daar hebben we allemaal niets aan, omdat daar geen files aan hangen. Deze willen we er dus uitfilteren en we willen dit flaggen als foutieve input. Jq wederom to the rescue:

$ jq -c '.items[]| select(.result.objectType != "program" and .result.objectType != "segment")|{ id: .id, type: .result.objectType }' out/mids.??? >bad-type
$ wc -l bad-type
1480 bad-type

Programs zonder locations

Er blijken mids van type program of segment te zijn waar geen locations aan gelinked zijn. Daar kunnen we ook niets mee. Dus weg dermee

$ jq -c  '.items[]| select(.result.objectType == "program" or .result.objectType == "segment")|select(.result|.locations |length == 0)|{ id: .id, locations: .result|.locations |length  }' out/mids.??? > no-locations
$ wc -l no-locations 
7206 no-locations

Beste bitrate

Een ID kan meerdere locations hebben (1:n relatie). Daarvan willen we graag degene met de hoogste bitrate kiezen. Dat kan wederom in jq met max_by:

$ jq -c  '.items[]| select(.result.objectType == "program" or .result.objectType == "segment")|select(.result|.locations |length > 0)|{ id: .id, url: .result.locations|max_by(.avAttributes.bitrate).programUrl }' out/mids.???

Maar, (zie even verderop) hiermee selecteren we veel sub+http content en dat wil ik niet, want daar heb ik de bestanden helemaal niet van. Dus die willen we uitfilteren. Dit zou er dan zo uit kunnen zien:

$ jq -c  '.items[]| select(.result.objectType == "program" or .result.objectType == "segment")|select(.result|.locations |length > 0)|{ id: .id, url: .result.locations |[ .[]|select(.programUrl|contains("sub+http")|not) ]|max_by(.avAttributes.bitrate).programUrl }' out/mids.???

Verder blijkt dat er sinds kort ook

npo://internetvod.omroep.nl/<ID>

style urls in POMs zitten (ik denk om NEP content mee aan te geven). Daar kan ik ook niets mee dus die moeten er ook uitgefilted worden.

Disclaimer: een jq guru kan dit vast beter. Dit is alleen maar wat ik zo snel bij elkaar gecobbled kon krijgen en werkt. Een probleem wel in deze setup is dat als er nu mids zijn waar uitsluitend sub+http locations aanhangen dan zegt de eerste test dat er wel locations zijn, maar de 2e gooit ze vervolgens allemaal weg. Verderop werken we daar omheen door null expliciet als location te herkennen en het mid als poms id te interpreteren. Dat werkt.

Uiteindelijke filter

In het kader van leesbaarheid stoppen we de filter expressie maar in een losse file, dan kan het een beetje geformatteerd worden:

$ cat filter.jq
.items[]|
select(.result.objectType == "program" or .result.objectType == "segment")|
select(.result|.locations | length > 0)|
{
  id: .id,
  url: .result.locations |
    [ 
        .[]|
        select(.avAttributes.avFileFormat == "MP4" or
                                .avAttributes.avFileFormat == "MP3" or
                                .avAttributes.avFileFormat == "H264" or
                                .avAttributes.avFileFormat == "M4V" )|
        select(.programUrl|contains("sub+http")|not)|
        select(.programUrl|contains("npo://")|not) |
        select(.programUrl|contains("npo+drm://")|not)
    ]|
    max_by(.avAttributes.bitrate).programUrl,
}

$ jq -c  -f filter.jq out/mids.??? >data
$ wc -l data
71207 data
$ head -3 data
{"id":"10act0505Canadezen","url":"odi+http://odi.omroep.nl/video/wmv_bb/10act0505Canadezen"}
{"id":"10act1002CDA","url":"odi+http://odi.omroep.nl/video/wvc1_std/10act1002CDA"}
{"id":"11act0206Pieter","url":"odi+http://odi.omroep.nl/video/wvc1_std/11act0206Pieter"}

Kiezen location

Wat voor types locaties hebben we eigenlijk? (onderstaand is gedraaid op de data voordat daar de sub+http urls uitgehaald waren. Op de uiteindelijke data is de verhouding iets anders omdat in die gevallen bijna allemaal odi+http urls geselecteerd zijn)

$ jq . data | grep /|sed 's#\(//[^/?]*\).*#\1#' |sort|uniq -c|sort -n
      1   "url": "http://content.omrep.nl
      1   "url": "http://download
      1   "url": "http://flashserver.rtvdrenthe.nl
      1   "url": "http://radiobox.omroep.nl
      1   "url": "http://weblogs.vpro.nl
      1   "url": "http://www.publiekeomroep.nl
      1   "url": "mp3://moby.vpro.nl
      1   "url": "odiw+http://odi.omroep.nl
      1   "url": "rtsp://halo.triple-it.nl:554
      1   "url": "rtsp://streaming.xwits.nl
      2   "url": "file://rtmpe:
      2   "url": "ftp://upload-extern.omroep.nl
      2   "url": "http://content1c.omroep.nl
      2   "url": "http://files.vpro.nl
      3   "url": "http://content1b.omroep.nl
      3   "url": "http://content1d.omroep.nl
      3   "url": "http://www.youtube.com
      4   "url": "odiw+http://livestreams.omroep.nl
      5   "url": "http://video.omroep.nl
      6   "url": "ftp://powned02@upload-extern.omroep.nl
     12   "url": "http://content1a.omroep.nl
     18   "url": "odip+http://odi.omroep.nl
     18   "url": "rtsp://halo.triple-it.nl
     49   "url": "http://download.eo.nl
     78   "url": "http://player.omroep.nl
    756   "url": "sub+http://npoplus.nl
   2232   "url": "sub+http://tvvod.omroep.nl
   2391   "url": "sub+http://npo.npoplus.nl
   3224   "url": "odis+http://content.omroep.nl
   5498   "url": "http://radiobox2.omroep.nl
   7577   "url": "http://download.omroep.nl
   8571   "url": "http://content.omroep.nl
  11476   "url": "http://cgi.omroep.nl
  29428   "url": "odi+http://odi.omroep.nl

Je ziet dat hier wat rommel in zit. Typo's, mensen die het niet begrepen hebben enzo. De bovenste helft van het lijstje laat ik voor wat het is. De onderste helft moeten we eens beter bestuderen:

sub+http integratie

Er zijn een paar duizend urls van de vorm “sub+http”. Deze wijzen naar npoplus en tvvod

Wat is de structuur van deze links?

$ grep sub+http data |sed -e 's#.*sub+http://##' -e 's#/[^/]*$##'|sort |uniq -c|sort -n
     12 npoplus.nl/video/h264_hr
     61 tvvod.omroep.nl/video/MPEG2_3500
    333 npoplus.nl/video/mpeg2_plus
    411 npoplus.nl/video/mpeg2_hr
   1071 npo.npoplus.nl/video/mpeg2_plus
   1320 npo.npoplus.nl/video/MXF
   2171 tvvod.omroep.nl/video/mpeg2_hr

In de grote-boze jq query hierboven zijn deze versies -denk ik- gekozen omdat ze de hoogste bitrates hadden. Maar nu is dat eigenlijk niet handig. De urls hebben allemaal een PRID in zich, dus we kunnen (zie hieronder) bij ODI te raad gaan of die iets voor ons heeft. Maar eigenlijk is het misschien slimmer om deze maar gewoon niet mee te nemen en ze in jq bij voorbaat uit te sluiten.

In de tussentijd nog weer wat jq bijgeleerd. Beschouw deze json file:

[
        { "foo": "bar",         "bar": "meh" },
        { "foo": "blup",        "bar": "whatever" },
        { "foo": "wibble",      "bar": "wop" }
]

Stel nu dat ik de entries waar key “foo” de substring “blu” heeft niet wil. Hoe regelen we dat?

$ jq '.[]|select(.foo|contains("blu")|not)' test.json 
{
  "foo": "bar",
  "bar": "meh"
}
{
  "foo": "wibble",
  "bar": "wop"
}

(mooie mentale hersengymnastiek vind ik die jq pipes trouwens, vooral zo'n |not.) Bovenstaande constructie gebruiken we om de sub+http zaken weg te filteren. Dat is deze regel in het uiteindelijke jq filter:

[ .[]|select(.programUrl|contains("sub+http")|not) ]|

radiobox integratie integratie

Alle radiobox links verwijzen uiteindelijk naar het download platform. We kunnen alle radiobox urls aan radiobox voeren. Die levert je dan wel een 302 naar de download link. Voorbeeld:

$ curl -D - http://radiobox2.omroep.nl/videofragment/file/5843/fragment.mp4
HTTP/1.1 302 Found
Date: Tue, 11 Apr 2017 12:33:29 GMT
Server: Apache/2.4.23 (Unix) PHP/5.3.29
X-Powered-By: PHP/5.3.29
Location: http://download.omroep.nl/portal/radiomanager/video_archive/radio6/2013/06/03/340-hegezelligoverdevloerdeel1.mp4
[en nog wat meer headers]

Hier zie je meteen al dat je zonder de radiobox database nooit zelf die mapping (/videofragment/file/5843/fragment.mp4 → /portal/radiomanager/video_archive/radio6/2013/06/03/340-hegezelligoverdevloerdeel1.mp4) gaat kunnen maken.

Dus hier rest ons niets anders dan alle radiobox urls bij radiobox te resolven. Ik vind het handig om dit even vantevoren te doen, zodat het uiteindelijke script alleen een lookup hoef te doen in de data die we in deze fase genereren. Daar heb ik het volgende scriptje voor geschreven:

$ cat rbx_resolve

PATH=/usr/bin:/bin
hdrs=$(mktemp -t rbx_resolve.XXXXXX)
while IFS=, read id url; do
        url=${url#\"url\":\"}; url=${url%\"\}}
        id=${id#\{\"id\":\"}; id=${id%\"}
        curl -s --fail -D $hdrs --output /dev/null "$url" &&
                awk -v id="$id" '/^Location/ { print id,$2; }' $hdrs
done
rm -f $hdrs

En als volgt gedraaid:

$ grep radiobox2 data | ./rbx_resolve  >rbx_map

Omdat het maar een heel dom scriptje is dat niets paralelliseert duurt het even; reken een minuut of 5 om alle radiobox urls te resolven.

En dan komt daar een lijstje uit dat er zo uit ziet:

$ head -3 rbx_map
POMS_AT_1012052 http://download.omroep.nl/portal/radiomanager/rm3-radio1/audiofragments/21/20648-Reportage_deel_twee.mp3
POMS_AT_1012053 http://download.omroep.nl/portal/radiomanager/rm3-radio1/audiofragments/21/20993-Brein_in_de_rechtszaal.mp3
POMS_AT_1012054 http://download.omroep.nl/portal/radiomanager/rm3-radio1/audiofragments/22/21174-Kloosterleven.mp3

Deze data gaat verderop in het uiteindelijke glue scriptje weer gebruikt worden.

download, content en cgi integratie

Het download platform is onder een aantal namen bekend, die allemaal synoniemen voor elkaar zijn:

Deze wijzen gewoon naar ons download platform. Daarnaast hebben (hadden) we het zgn “streams script”. Dit verwijst naar het streaming platform. Urls zien er zoiets uit:

http://cgi.omroep.nl/cgi-bin/streams?/vpro/39488696/windowsmedia.asf?title=Charles Frail sessie  Motel Mozaique 12-04-2008&author=Charles Frail"

(ja, je ziet het goed, slimmerds die 2x ? in een url zetten…) Dit kunnen we redelijk makkelijk masseren naar een downloadable locatie, door contentslurp.omroep.nl ook bv een /media sectie te geven die naar de streaming docroot (/e/ap/media) wijst.

ODI Integratie

Voor alle odi-style URLs hebben we de informatie uit ODI nodig om te bedenken welk bestand er gekopieerd moet gaan worden. In ODI heb je meerdere zgn “publicatie opties”, en die heb je weer nodig om het uiteindelijke pad af te kunnen leiden. Ik kies er maar voor om de informatie direct uit de odi database te trekken:

$ ssh tab-as68
$ mysql --host=10.15.4.18 --user=odi --password='**************' odi_db
MariaDB [odi_db]> select * from puboption;
+----+--------------+-----------+--------------+----------------+---------------------+
| id | puboption_id | puboption | family       | prefix         | updated             |
+----+--------------+-----------+--------------+----------------+---------------------+
|  1 |            1 | wmv_bb    | windowsmedia | /ceres         | 2015-02-02 15:27:13 |
|  2 |            2 | wmv_sb    | windowsmedia | /ceres         | 2015-02-02 15:27:13 |
|  3 |           10 | wvc1_std  | windowsmedia | /ceres         | 2015-02-02 15:27:13 |
|  4 |            4 | h264_bb   | download     | /ceresodi/h264 | 2015-02-04 10:14:54 |
|  5 |            5 | h264_sb   | download     | /ceresodi/h264 | 2015-02-04 10:14:54 |
|  6 |            9 | h264_std  | download     | /ceresodi/h264 | 2015-02-04 10:14:54 |
|  7 |           12 | adaptive  | adaptive     |                | 2015-02-04 10:14:54 |
+----+--------------+-----------+--------------+----------------+---------------------+
7 rows in set (0.01 sec)

Voorbeeldje voor windowsmedia:

MariaDB [odi_db]> select episode_prid,location from episode_puboption where puboption_id=10 limit 3;
+--------------+-------------------------------------------------------+
| episode_prid | location                                              |
+--------------+-------------------------------------------------------+
| AVRO_1353288 | /ceres/1/avro/rest/2010/AVRO_1353288/std.20100810.wmv |
| AVRO_1367472 | /ceres/1/avro/rest/2010/AVRO_1367472/std.20100810.wmv |
| AVRO_1378275 | /ceres/1/avro/rest/2010/AVRO_1378275/std.20100810.wmv |
+--------------+-------------------------------------------------------+
3 rows in set (0.00 sec)

Da's mooi. Dat betekent dat we ODI redelijk makkelijk leeg kunnen trekken. (onderstaand er van uitgaande dat er een .my.cnf met valide credentials staat)

$ mysql -B --skip-column-names -e 'select b.puboption,a.episode_prid,a.location from episode_puboption as a, puboption as b where a.puboption_id = b.puboption_id' odi_db | gzip -c >odi_map.gz
$ zcat odi_map.gz |wc -l
956707
$ zcat odi_map.gz |head -3
h264_bb AVRO_1353288    /ceres/1/avro/rest/2010/AVRO_1353288/bb.20100810.m4v
h264_sb AVRO_1353288    /ceres/1/avro/rest/2010/AVRO_1353288/sb.20100810.m4v
h264_std        AVRO_1353288    /ceres/1/avro/rest/2010/AVRO_1353288/std.20100810.m4v

De volgende vraag is nu: hoe bepaal ik de ODI publicatie optie aan de hand van een odi url? Ik zie de volgende ODI style urls terugkomen:

$ grep ':"odi[a-z]*\+' data |sed -e 's#://.*##' -e 's#^.*:"##'|sort|uniq -c
  29428 odi+http
     18 odip+http
   3224 odis+http
      5 odiw+http

Reverse engineerend denk ik dat dit de volgende betekenissen heeft:

type betekenis
odi regulier, zoals ik ken, odi, puboption valt uit uri te herleiden. Alle odi+http urls verwijzen altijd naar odi.omroep.nl
odip zo te zien voor adaptive dingen
odis Wordt gebruikt voor protected content, voorbeeld odis+http://content.omroep.nl/vpro/protected/luisterpaal/video/2012/06/12/AngusStone3sngs.mp4. Grappig genoeg hoef ik dat niet aan odi te vragen en kan dit gewoon als download url behandeld worden
odiw Dit zijn livestreams. Deze kunnen genegeerd worden

Hoe zien odi+http uri's eruit?

$ grep odi+http data |sed -e 's#.*odi.omroep.nl/##' -e 's#/[^/]*$##'|sort|uniq -c
     24 video/h264_bb
     44 video/h264_sb
   5913 video/h264_std
   6427 video/wmv_bb
      1 video/wmv_sb
  17019 video/wvc1_std

En dit mapped natuurlijk perfect op de puboptions van odi.

Glue alles aan elkaar

Alle onderdelen hebben we nu:

Gewapend met bovenstaande maps kunnen we een scriptje schrijven dat de vertaling van de diverse smaken odi urls doet.

Ik heb een perl (sorry…) scriptje geschreven om dit allemaal aan elkaar te lijmen. Dit levert een lijst met mappings mid → uri, waarbij alle uri's aan contentslurp.omroep.nl te voeren zijn. Dingen waar het script niets mee kon komen terecht in z'n errorlog. Redenen hiervoor kunnnen zijn:

$  ./dataglue.pl data >contentslurp_map 2>err
$ wc -l contentslurp_map err 
  71041 contentslurp_map
    166 err
  71207 total

Tot slot nog een paar opmerkingen:

  1. Dat poms zegt dat een link bestaat hoeft nog niet te betekenen dat dat ook werkelijk waar is. Het kan zomaar zijn dat een omroep deze content op het downloadplatform heef tverwijderd en dat niet in poms heeft bijgewerkt oid.
  2. adaptive links zijn links naar een directory. Daarvoor wil je alle bestanden in de directory downloaden (.ism en -meestal- 4 .ismv bestanden)
  3. Naast h264 en adaptive is er ook windowsmedia en mp3 content.
  4. En daarnaast is er ook nog andere random cruft die omroepen erin gestopt hebben. Ik zie een jpg bestand, maar bijvoorbeeld ook realmedia, flash video, mp2, mov…
  5. De URL encoding in poms is niet bepaald consistent. Je kan dus urls met 'foo bar' tegenkomen, maar ook met 'foo%20bar' of 'foo+bar'. Hou daar rekening mee als je zelf nette url encoding wilt doen.

Nabrander Vragen

Nadat ik bovenstaand stukje geschreven had, heb ik nog minimaal 5x een verzoek vanuit Online gekregen om dit script nog een keer te runnen met een andere set aan mids. Bij de nmiddels voor-voor-voor-voor laatste keer mondde dat uit in deze mailconversatie:

Date: Mon, 25 Sep 2017 13:18:11 +0000
From: Dennis Verhoeven Dennis.Verhoeven@npo.nl
To: Dick Snippe Dick.Snippe@NPO.nl
CC: Nick Ceton Nick.Ceton@npo.nl, Egon Verharen Egon.Verharen@NPO.nl
Subject: RE: Migratielijst v NEP

Hoi Dick,

Dank voor de snelle en gedetailleerde reactie. Ik heb een vraag over de items
+waarvan jij aangeeft dat ze niet in POMS zitten, de items uit deze lijsten
+komen namelijk allemaal uit POMS. Kan het zijn dat ik iets over het hoofd zie?
+Het gaat gelukkig om een klein aantal, maar ben toch even benieuwd te weten
+waar dit zit.

Groet,
Dennis.


—–Oorspronkelijk bericht—–
Van: Dick Snippe [mailto:Dick.Snippe@npo.nl]
Verzonden: maandag 25 september 2017 14:58
Aan: Dennis Verhoeven Dennis.Verhoeven@npo.nl
CC: Nick Ceton Nick.Ceton@npo.nl; Egon Verharen Egon.Verharen@NPO.nl
Onderwerp: Re: Migratielijst v NEP

On Mon, Sep 25, 2017 at 11:45:47AM +0000, Dennis Verhoeven wrote:

> Het heeft wat langer geduurd, maar dit is de uiteindelijke lijst met items die
+volgens diverse criteria nog gemigreerd moeten worden. De CSV is in principe
+een tekstfile met maar 1 PRID per regel. Zou jij deze zoals we dat eerder
+besproken/gevraagd hebben kunnen omzetten naar een lijst met locaties opdat NEP
+deze kan migreren?

Zeker. Jij hebt mij een lijst aangeleverd met 122671 items.
Daar zaten wel duplicaten in; ik (nouja, mijn computer) telde 117646 unieke
+ID's. Na het wegfilteren van syntactisch incorrecte MIDs (met spaties erin
+enzo) bleven er nog 117639 over.
Daarvan kwam weer niet alles in POMS voor. Er werden 117489 items gevonden in
+POMS. Die kon ik uiteindelijk door mijn scriptje halen.
Daarvan konden er 117065 geresolved worden en 424 daar was wat mee.

Dat is wel een goede vraag. Maar hoe gaan we daar achter komen?

Om te beginnen wil ik weten welke MIDs dat zijn:

$ sort in/mids.* >mids.in
$ wc -l mids.in
117639 mids.in
###Die hebben ook allemaal een POMS id:
###$ jq '.items[].id' out/mids.??? | tr -d '"' | sort >mids.poms
###$ wc -l mids.poms
###117639 mids.poms
$ jq '.id' data|tr -d '"' | sort >mids.found
$ wc -l mids.found 
117489 mids.found
$ comm -23 mids.in mids.found >mids.notfound
$ get api/media/multiple ids=$(tr '\n' ',' <mids.notfound ) > data.notfound 

Vervolgens kunnen we die data.notfound nog eens wat nader bestuderen.