Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
wiki:user:dick:mids [2019/03/26 23:42]
dick [Glue alles aan elkaar]
wiki:user:dick:mids [2019/04/26 10:34] (current)
Line 1: Line 1:
 +~~META:
 +title = Vertaal MIDs naar filesysteem paden
 +~~
 +<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:
 +  - Haal via de POMS api bij elk MID de onderliggende ''​programUrl''​ op
 +  - Bepaal aan de hand van hoe die url eruit ziet of je nog meer processing moet doen:
 +  - Kies van het lijstje programUrl'​s degene die je het beste lijkt (hoogste bitrate, h264 > windosmedia,​ e.d.)
 +  - 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:
 +  * Er zou potentieel POMS content tussen kunnen zitten die in POMS gemarkeerd staat als zijnde "​REVOKED"​
 +  * Er zit content tussen die in het NPO download platform over zgn [[http://​hosting.omroep.nl/​sterretje-cluster:​content-hosting#​hotlink_bescherming|hotlink bescherming]] beschikt
 +
 +
 +====== Experimenten POMS api ======
 +  * http://​wiki.publiekeomroep.nl/​display/​npoapi/​Home
 +  * http://​rs.poms.omroep.nl/​v1/​docs/​api/​
 +
 +===== Api downloaden en uitproberen =====
 +Ik gebruik jq om JSON te processn, da's gewoon een rpm.
 +
 +<​code>​
 +$ 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
 +</​code>​
 +
 +===== Stoeien met jq om nuttige info te verkrijgen =====
 +
 +<​code>​
 +$ ./​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...
 +</​code>​
 +
 +<​code>​
 +$ ./​media/​get.sh RBX_RA4_4628952| jq '​.locations[]|.programUrl'​
 +"​http://​radiobox2.omroep.nl/​broadcaststream/​file/​478896.mp3"​
 +</​code>​
 +
 +Maar eigenlijk wil ik in 1 klap een lijst aan MIDs kunnen geven.
 +<​code>​
 +$ . ./​api-functions.sh
 +get api/​media/​multiple ids=POW_00470026,​POW_00135450|jq
 +</​code>​
 +
 +Hoe krijgen we daar de gewenste info uit?
 +<​code>​
 +$ 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"​
 +</​code>​
 +
 +Met nog een pietsie meer jq-fu zou hier een handig lijstje uit moeten
 +kunnen komen, zou je zeggen.
 +<​code>​
 +$ 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"​
 +  ]
 +}
 +</​code>​
 +
 +====== Data cleanup ======
 +Ik heb van Jantine 10 files gekregen:
 +<​code>​
 +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
 +</​code>​
 +
 +maar daar zit nog wat rommel in (lege regels, tekstkopjes)
 +Als volgt gecleaned:
 +<​code>​
 +$ 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
 +</​code>​
 +
 +Wat is dan de rommel die niet meegenomen is?
 +<​code>​
 +$ 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
 +</​code>​
 +
 +Verder blijken er een hoop duplicaten in te zitten:
 +<​code>​
 +$ uniq -d mids|wc -l
 +1624
 +</​code>​
 +
 +Laten we die er nog maar even uitvissen
 +<​code>​
 +$ uniq mids >​mids.tmp
 +$ mv mids.tmp mids
 +$ wc -l mids
 +79893 mids
 +</​code>​
 +
 +====== 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
 +<​code>​
 +### 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
 +</​code>​
 +
 +====== 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.)
 +<​code>​
 +$ 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)
 +</​code>​
 +
 +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?
 +<​code>​
 + $ jq '​.items[]|{ id: .id, type: .result.objectType }' out/​mids.???​|grep type|sort -u
 +  "​type":​ "​group"​
 +  "​type":​ null
 +  "​type":​ "​program"​
 +  "​type":​ "​segment"​
 +</​code>​
 +
 +===== 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:
 +<​code>​
 +$ 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
 +</​code>​
 +
 +===== 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
 +<​code>​
 +$ 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
 +</​code>​
 +
 +===== 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:
 +<​code>​
 +$ 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"​}
 +</​code>​
 +
 +====== 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)
 +<​code>​
 +$ 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
 +</​code>​
 +
 +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?
 +<​code>​
 +$ 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
 +</​code>​
 +
 +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:
 +<​code>​
 +[
 +        { "​foo":​ "​bar", ​        "​bar":​ "​meh"​ },
 +        { "​foo":​ "​blup", ​       "​bar":​ "​whatever"​ },
 +        { "​foo":​ "​wibble", ​     "​bar":​ "​wop"​ }
 +]
 +</​code>​
 +
 +Stel nu dat ik de entries waar key "​foo"​ de substring "​blu"​ heeft **niet** wil.
 +Hoe regelen we dat?
 +<​code>​
 +$ jq '​.[]|select(.foo|contains("​blu"​)|not)'​ test.json ​
 +{
 +  "​foo":​ "​bar",​
 +  "​bar":​ "​meh"​
 +}
 +{
 +  "​foo":​ "​wibble",​
 +  "​bar":​ "​wop"​
 +}
 +</​code>​
 +
 +(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:
 +<​code>​
 +$ 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]
 +</​code>​
 +
 +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:
 +<​code>​
 +$ 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
 +</​code>​
 +
 +En als volgt gedraaid:
 +<​code>​
 +$ grep radiobox2 data | ./​rbx_resolve ​ >rbx_map
 +</​code>​
 +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:
 +<​code>​
 +$ 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
 +</​code>​
 +
 +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:
 +  * download.omroep.nl
 +  * content.omroep.nl
 +  * download.eo.nl
 +  * video.omroep.nl
 +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:
 +<​code>​
 +$ 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)
 +</​code>​
 +
 +Voorbeeldje voor windowsmedia:​
 +<​code>​
 +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)
 +</​code>​
 +
 +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)
 +<​code>​
 +$ 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
 +</​code>​
 +
 +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:
 +<​code>​
 +$ 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
 +</​code>​
 +
 +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?
 +<​code>​
 +$ 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
 +</​code>​
 +
 +En dit mapped natuurlijk perfect op de puboptions van odi.
 +
 +====== Glue alles aan elkaar ======
 +Alle onderdelen hebben we nu:
 +  * Een file genaamd "​data"​ met daarin een mapping ''​mid -> url''​ zoals die in POMS staat
 +  * Een file "​rbx_map"​ met daarin een mapping ''​odi url -> download url''​ voor radiobox style urls
 +  * Een file "​odi_map"​ met daarin een mapping ''​PRID + puboption -> location''​
 +Gewapend met bovenstaande maps kunnen we een scriptje schrijven dat
 +de vertaling van de diverse smaken odi urls doet.
 +
 +Ik heb een perl (sorry...) {{ :​wiki:​user:​dick:​dataglue.pl.docuwiki-is-stom.txt|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:
 +  * "​unknown ODI prid/​pubopt":​ ODI kende deze prid/​publicatie optie combinatie niet
 +  * "no ODI match found":​ Urls van de stijl ''​sub+http''​ kunnen we niet resolven. Maar er zit wel een PRID in de url dat aan odi gevoerd kan worden om alsnog tot content te komen. Deze error krijg je bij PRID's die ODI niet kent.
 +  * "​cannot handle <​url>":​ Het script kon niets met deze url. Dit speelt vooral voor urls van de stijl ''​http://​player.omroep.nl/?​aflID=...''​. player.omroep.nl bestaat niet (meer) en ik weet niet hoe deze aflevering id's nog te herleiden zijn.
 +  * "​http://​radiobox2.omroep.nl/​... does not resolve"​. In POMS zat blijkbaar een url naar radiobox, welke bij radiobox niet bekend was (en aldaar een 404 geeft)
 +
 +<​code>​
 +$  ./​dataglue.pl data >​contentslurp_map 2>err
 +$ wc -l contentslurp_map err 
 +  71041 contentslurp_map
 +    166 err
 +  71207 total
 +</​code>​
 +
 +Tot slot nog een paar opmerkingen:​
 +  - 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.
 +  - adaptive links zijn links naar een **directory**. Daarvoor wil je alle bestanden in de directory downloaden (.ism en -meestal- 4 .ismv bestanden)
 +  - Naast h264 en adaptive is er ook windowsmedia en mp3 content.
 +  - 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...
 +  - 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:
 +<​code>​
 +$ 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 ​
 +</​code>​
 +
 +Vervolgens kunnen we die ''​data.notfound''​ nog eens wat nader
 +bestuderen.