#!/usr/bin/env python from __future__ import division import lxml import lxml.etree import ox import os import json import sys import re source = sys.argv[1] data = [] tree = lxml.etree.parse(source) api = ox.API('https://pad.ma/api/') if os.path.exists('sot.json'): sot = json.load(open('sot.json')) else: sot = api.find({ 'query': { 'conditions': [{'key': 'list', 'value': 'zi:SOT'}] }, 'keys': ['id', 'title', 'duration'], 'range': [0, 5000] })['data']['items'] with open('sot.json', 'w') as f: json.dump(sot, f, indent=2) def get_item(id): id = id.replace('_', ' ').replace('.MOV', '').replace('BT2C0662 3', 'BT2C0662') for data in sot: if id in data['title'].replace('/', ' '): return data['id'] for k in ('STK', 'MNK', 'BT2C'): id = id.replace(k, '').strip() for data in sot: if id in data['title'].replace('/', ' '): return data['id'] print 'missing', id durations = {data['id']: data['duration'] for data in sot} def parse_fps(rate): if rate.find('ntsc').text == 'TRUE': rate = int(rate.find('timebase').text) * 1000 / 1001 else: rate = int(rate.find('timebase').text) return rate tracks = [] seq = tree.getroot()[0] fps = parse_fps(seq.find('rate')) v = seq.find('media').find('video') for t in v.xpath('.//track'): track = [] for clipitem in t.xpath('.//clipitem'): _id = clipitem.attrib['id'].strip().split('-Apple')[0] _id = _id.replace('Shampoo flask', '').replace(' HDR', '').replace(' hdr', '').replace('pro res 422', '').replace(' cool', '').strip() _id = re.sub(' \d\d?$', '', _id) #start/end - position on timeline #in/out - in/out in clip clip_fps = parse_fps(clipitem.find('rate')) _in = int(clipitem.findall('in')[0].text) _out = int(clipitem.findall('out')[0].text) duration = _out - _in _start = int(clipitem.findall('start')[0].text) _end = int(clipitem.findall('end')[0].text) if _start == -1 and _end == -1: print 'strange', _start, _end, _in, _out, _id continue if _start == -1: _start = _end - duration elif _end == -1: _end = _start + duration if filter(lambda x: x <0, [_start, _end, _in, _out]): print 'why -?', _start, _end, _in, _out, _id if _out - _in != _end - _start: print '??', _in, _out, _out-_in, 'vs', _start, _end, _end-_start, _id if _start > -1 and _end > -1: track.append({ 'in': _in / fps, 'out': _out / fps, 'start': _start / fps, 'end': _end / fps, 'file': _id, 'id': get_item(_id), 'track': len(tracks) }) if track: tracks.append(track) with open('/tmp/tracks.json', 'w') as f: json.dump(tracks, f, indent=2, sort_keys=True) for i, track in enumerate(tracks): with open('/tmp/tracks%s.json' % i, 'w') as f: json.dump(track, f, indent=2, sort_keys=True) def flatten_tracks(tracks): def split_at_overlaps(clip): offset_start = clip['start'] offset_clip = clip['in'] points = [clip['start'], clip['end']] for track in tracks: for c in track: if c['track'] != clip['track'] and c['start'] > -1 and c['end'] > -1: if c['start' ] > clip['start'] and c['start'] < clip['end']: points.append(c['start']) if c['end' ] > clip['start'] and c['end'] < clip['end']: points.append(c['end']) print clip['track'], points clips = [] for i, point in enumerate(points[:-1]): offset_in = point - offset_start duration = points[i+1] - point if duration > 0: clips.append({ 'in': offset_clip + offset_in, 'out': offset_clip + offset_in + duration, 'start': point, 'end': points[i+1], 'track': clip['track'], 'id': clip['id'] }) return clips clips = [] for track in tracks: for clip in track: clips += split_at_overlaps(clip) for clip in clips: for c in clips: if c['track'] > clip['track']: if c['start'] <= clip['start'] and c['end'] >= clip['end']: clip['delete'] = True _clips = sorted([c for c in clips if not c.get('delete')], key=lambda a: a['start']) clips = [] for c in _clips: if clips and clips[-1]['out'] == c['in'] and clips[-1]['id'] == c['id']: print 'join', clips[-1], c clips[-1]['end'] = c['end'] clips[-1]['out'] = c['out'] else: clips.append(c) position = None for c in clips: if position == None: position = c['start'] if c['start'] != position: print 'wrong start', c['start'], position, abs(position - c['start']) position += c['out'] - c['in'] return clips timeline = flatten_tracks(tracks) pandora_edit = [] for c in timeline: if c['id']: if c['out'] > durations[c['id']] or c['in'] > durations[c['id']] or c['in'] < 0 or c['out'] <= c['in']: print 'invalid in/out', c, durations[c['id']] else: pandora_edit.append({ 'in': c['in'], 'out': c['out'], 'item': c['id'] }) ''' ''' print len(pandora_edit) #print json.dumps(timeline, indent=2, sort_keys=True) print json.dumps(pandora_edit, indent=2, sort_keys=True) with open(os.path.expanduser('~/.ox/client.padma.json')) as f: settings = json.load(f) r = api.signin(username=settings['username'], password=settings['password']) assert(r['status']['code'] == 200) print 'add clips', len(pandora_edit) #print pandora_edit #r = api.addEdit({ # 'name': 'Ship of Theseus', # 'clips': pandora_edit #}) #print r['data'].get('id') or r clips = [c['id'] for c in api.getEdit({'id': 'j:Ship of Theseus', 'keys': ['clips']})['data']['clips']] if clips: api.removeClips({ 'edit': 'j:Ship of Theseus', 'ids': clips }) step = 100 while pandora_edit: clips = pandora_edit[:step] pandora_edit = pandora_edit[step:] print 'add', len(clips), 'todo', len(pandora_edit) r = api.addClips({ 'edit': 'j:Ship of Theseus', 'clips': clips }) print 'total added', len(r and r.get('data', {}).get('clips') or 0)