Forum Archive

how to get last video on iphone?

frankL

I've been looking at the photos module documentation and have managed some rudimentary scripts to access images on my iphone. The documentation seems to indicate that videos can also be accessed but when I've tried:

videos = photos.get_assets(media_type='video', include_hidden=True)
last_video = videos[-1]
video = last_video.get_ui_image()
video.show()

It only displays the last photo, not video. What am I doing wrong? Thanks

cvp

@frankL said:

video = last_video.get_ui_image()

This line implies that you take only one image.
What do you want to do?
Copy a video from the camera roll to....?

cvp

@frankL this copies picked video to Pythonista local files

import photos
from objc_util import *
import time
import shutil
import os

videos = photos.get_assets(media_type='video')
assets = photos.pick_asset(assets=videos,multi=True)
#print(dir)

options=ObjCClass('PHVideoRequestOptions').new()
options.version=1   #PHVideoRequestOptionsVersionOriginal, use 0 for edited versions.
image_manager=ObjCClass('PHImageManager').defaultManager()

handled_assets=[]

def handleAsset(_obj,asset, audioMix, info):
    A=ObjCInstance(asset)
    '''I am just appending to handled_assets to process later'''
    handled_assets.append(A)
    '''
    # alternatively, handle inside handleAsset.  maybe need a threading.Lock here to ensure you are not sending storbinaries in parallel
    with open(str(A.resolvedURL().resourceSpecifier()),'rb') as fp:
        fro.storbinary(......)
    '''

handlerblock=ObjCBlock(handleAsset, argtypes=[c_void_p,]*4)

for A in assets:
    #these are PHAssets
    image_manager.requestAVAssetForVideo(A, 
                        options=options, 
                        resultHandler=handlerblock)

while len(handled_assets) < len(assets):
    '''wait for the asynchronous process to complete'''
    time.sleep(1)

for A in handled_assets:
    url = str(A.resolvedURL().resourceSpecifier())
    local = os.path.basename(url)
    print(url)
    shutil.copy(url,local)
frankL

Thank you. That allows me to find my videos, but how do I play them either in the console or otherwise?

cvp

@frankL try this @JonB ' s player

frankL

The player works perfectly. If I wanted to pick a video and get it's url and save that for later, how would I pass that url to the player directly and not from the pick_asset call?

cvp

@frankL in the script, you can print(u) to get an url like assets-library://asset/asset.MOV?id=C03ABFB4-08F3-4A00-B626-BB9A01B293B2&ext=MOV

So, if you save this string in a file, you can reuse with these lines

url = nsurl('assets-library://asset/asset.MOV?id=C03ABFB4-08F3-4A00-B626-BB9A01B293B2&ext=MOV')
u=ObjCClass('AVURLAsset').alloc().initWithURL_options_(url,None)
i=AVPlayerItem.playerItemWithAsset_(u)
p=AVPlayer.playerWithPlayerItem_(i)
videolayer=AVPlayerLayer.playerLayerWithPlayer_(p)
frankL

I printed the url, substituted it as you suggested, but after:

url = nsurl('assets-library://asset/asset.MOV?id=7C43F2B6-68DB-4314-80A7-34C6F92E8C8A&ext=MOV')
C03ABFB4-08F3-4A00-B626-BB9A01B293B2&ext=MOV')
u=ObjCClass('AVURLAsset').alloc().initWithURL_options_(url,None)

print(u) returns None
I must still be missing something.

cvp

@frankL ok, sorry, print(u) is erroneous, I wanted to say print(url), what you did.
But now you have the url as a string, you can save it where you want and read it later to only
Display via some script lines of my post, without passing via pick

cvp

@frankL this script only plays a video. Up to you to save the url in a file in the initial pick script and to read it and play in this script

from objc_util import *
AVPlayerItem=ObjCClass('AVPlayerItem')
AVPlayer=ObjCClass('AVPlayer')
AVPlayerLayer=ObjCClass('AVPlayerLayer')

url = nsurl('assets-library://asset/asset.MOV?id=C03ABFB4-08F3-4A00-B626-BB9A01B293B2&ext=MOV')
u=ObjCClass('AVURLAsset').alloc().initWithURL_options_(url,None)
i=AVPlayerItem.playerItemWithAsset_(u)
p=AVPlayer.playerWithPlayerItem_(i)
videolayer=AVPlayerLayer.playerLayerWithPlayer_(p)

import ui
v=ui.View(frame=(0,0,500,500))
V=ObjCInstance(v)
videolayer.frame=V.bounds()
V.layer().addSublayer_(videolayer)
v.present('sheet')

p.play()
frankL

That works perfectly, thank you.
Is there some documentation on video players and objc that you could point me to so that I can get a better understanding of how this all works?

cvp

@frankL standard Apple doc contains all (and more) info needed, good luck

frankL

Thank you. I had only been looking at Pythonista 3 documentation and just recently came across the photos module. Photos doesn't appear to support much in the way of videos.
I appreciate all of your help.

frankL

Is there a simple way to add controls to the player such as pause, play, etc.?

cvp

@frankL try this

from objc_util import *
AVPlayerItem=ObjCClass('AVPlayerItem')
AVPlayer=ObjCClass('AVPlayer')
AVPlayerLayer=ObjCClass('AVPlayerLayer')

url = nsurl('assets-library://asset/asset.MOV?id=71F89028-7FA0-4C53-B6AD-6659BC8458D8&ext=MOV')
u=ObjCClass('AVURLAsset').alloc().initWithURL_options_(url,None)
i=AVPlayerItem.playerItemWithAsset_(u)
p=AVPlayer.playerWithPlayerItem_(i)
videolayer=AVPlayerLayer.playerLayerWithPlayer_(p)

import ui
v=ui.View(frame=(0,0,500,500))
V=ObjCInstance(v)
videolayer.frame=V.bounds()
V.layer().addSublayer_(videolayer)
v.present('sheet')

p.play()

bplay = ui.ButtonItem()
bplay.title = 'play'
def b_play_action(sender):
    p.play()
bplay.action = b_play_action

bpause = ui.ButtonItem()
bpause.title = 'pause'
def b_pause_action(sender):
    p.pause()
bpause.action = b_pause_action

v.right_button_items = (bplay, bpause)
cvp

@frankL you can even find an example of a slider in the minimal à player Of @JonB

frankL

Thank you. All that is running correctly now. How can I update the slider to indicate the elapsed time status of the video? The Apple documentation is very difficult to understand.

cvp

@frankL said:

How can I update the slider to indicate the elapsed time status of the video

from objc_util import *
import ui
AVPlayerItem=ObjCClass('AVPlayerItem')
AVPlayer=ObjCClass('AVPlayer')
AVPlayerLayer=ObjCClass('AVPlayerLayer')

url = nsurl('assets-library://asset/asset.MOV?id=71F89028-7FA0-4C53-B6AD-6659BC8458D8&ext=MOV')
u=ObjCClass('AVURLAsset').alloc().initWithURL_options_(url,None)
i=AVPlayerItem.playerItemWithAsset_(u)
p=AVPlayer.playerWithPlayerItem_(i)
videolayer=AVPlayerLayer.playerLayerWithPlayer_(p)

#define cmtime, for seeking
import ctypes
CMTimeValue=ctypes.c_int64
CMTimeScale=ctypes.c_int32
CMTimeFlags=ctypes.c_uint32
CMTimeEpoch=ctypes.c_int64
class CMTime(Structure):
   _fields_=[('value',CMTimeValue),
   ('timescale',CMTimeScale),
   ('flags',CMTimeFlags),
   ('epoch',CMTimeEpoch)]
   def __init__(self,value=0,timescale=1,flags=0,epoch=0):
      self.value=value
      self.timescale=timescale
      self.flags=flags
      self.epoch=epoch
c.CMTimeMakeWithSeconds.argtypes=[ctypes.c_double,ctypes.c_int32]
c.CMTimeMakeWithSeconds.restype=CMTime
c.CMTimeGetSeconds.argtypes=[CMTime]
c.CMTimeGetSeconds.restype=c_double


class MyView(ui.View):
    def __init__(self, *args, **kwargs):
        ui.View.__init__(self, *args, **kwargs)
        self.background_color = 'white'

        V=ObjCInstance(self)
        videolayer.frame=V.bounds()
        V.layer().addSublayer_(videolayer)

        bplay = ui.ButtonItem()
        bplay.title = 'play'
        def b_play_action(sender):
            p.play()
        bplay.action = b_play_action
        self.update_interval = 0        

        bpause = ui.ButtonItem()
        bpause.title = 'pause'
        def b_pause_action(sender):
            p.pause()
        bpause.action = b_pause_action      
        self.right_button_items = (bplay, bpause)

        slider=ui.Slider(frame=(0,0,self.width,20))     
        #sender.superview.name = str(sender.value*duration_sec)
        slider.action=self.slider_action
        slider.bring_to_front()
        self.slider = slider
        self.add_subview(slider)

    def update(self):
        s = p.currentTime().a/p.currentTime().b
        self.slider.value = s/duration_sec

    def slider_action(self, sender):
        self.seek(sender.value*duration_sec)

    @on_main_thread
    def seek(self,t):
        T=c.CMTimeMakeWithSeconds(t,1)
        p.seekToTime_(T,argtypes=[CMTime],restype=None)

v=MyView(frame=(0,0,500,500))
v.present('sheet')

duration=i.duration()
duration_sec=duration.a/duration.b
#print(duration_sec)

p.play()
v.update_interval = 0.1 

cvp

@frankL try until

v.update_interval = 1/60    
cvp

@frankL Is it what you wanted?

frankL

I see that your code works but I'm trying to implement it in a subview and I can't figure out how to use the v.update_interval method.

frankL

To clarify, I have a button in the main view that plays a video that the user selects from the main view. The button action instantiates a subview that runs the video and presents the slider, play, pause and stop buttons. The slider works to move the video playback manually but otherwise the slider doesn't display the elapsed time of the video. Any insight you can give me would be appreciated.

cvp

@frankL said:

how to use the v.update_interval method.

update_interval is not a method but an attribute setting thé interval in seconds between 2 calls to the update méthod in a subclassed view.

cvp

@frankL said:

Any insight you can give me would be appreciated

It would be easier to help if you post your script.

frankL

Here is the code. The function with the view for the video player is "play_action".

import ui
import csv
import os
import objc_util
from objc_util import *

#
def show_list_dialog(items=None, *args, **kwargs):
    items = items or []
    tbl = ui.TableView(**kwargs)
    tbl.data_source = ui.ListDataSource(items)
    my_sel = {'value': None}
    class MyTableViewDelegate (object):
        def tableview_did_select(self, tableview, section, row):
            my_sel['value'] = tableview.data_source.items[row]
            tableview.close()
    tbl.delegate = MyTableViewDelegate()
    tbl.present(style='sheet')
    tbl.wait_modal()
    return my_sel['value']
#
#
def open_video_ref():
    matrix=[]
    my_path=os.path. abspath("dance_video_ref.csv")
    with open(my_path,'r',encoding='utf-8') as reader:
        reader=csv.DictReader(reader)
        for row in reader:
            matrix.append([row['Index'], row['Dance'], row['Instructor'], row['Description'], row['Label'], row['url'], row['level'], row['duration']])
    return matrix
#
#              MAIN PROGRAM             #
#

#
w, h = ui.get_screen_size()
h -= 64
bh = bw = 80  # label height and button width
mg = 10  # margin
view = ui.View(name='Dance Lesson Videos', bg_color='#D98880', frame=(0, 0, w, h))

dance_instructor_value='Select Instructor(s)'
dance_instructor = ui.TextField(frame=(100,15,130,0),border_color='black', border_width=2, text=dance_instructor_value, bordered=True, font=('Arial Rounded MT Bold',15))
dance_instructor.height=30
dance_instructor.width=130
dance_instructor.enabled=False
view.add_subview(dance_instructor)

#
def instructor_action(sender):
    global dance_matrix
    matrix = open_video_ref()
    priority = int(dance_priority.text)
    dance_matrix = []
    for row in matrix:
        if priority == int(row[6]):
            dance_matrix.append(row)
    instructor_list = ['All']
    for row in dance_matrix:
        instructor = row[2]
        if instructor in instructor_list:
            continue
        else:
            instructor_list.append(instructor)
    f = (0, 0, 400, 300)
    try:
        result = show_list_dialog (instructor_list, frame=f, name='Select an Instructor')
        dance_instructor.text=result
        if dance_instructor.text != 'All':
            new_matrix = []
            for row in dance_matrix:
                if row[2] == dance_instructor.text:
                    new_matrix.append(row)
            dance_matrix = new_matrix
        dance_button.enabled=True
        search_dance.text = 'dance name'
    except:
        dance_instructor.text = 'try again'
    pattern_button.enabled=False
    pattern_video.text = 'dance pattern'
    play_button.enabled=False
    return
#
instructor_button = ui.Button(frame=(10,10,130,0),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=instructor_action, font=('Arial Rounded MT Bold',18))
instructor_button.title='Instrctr'
instructor_button.width=80
instructor_button.height=40
view.add_subview(instructor_button)

#
def priority_action(sender):
    matrix = open_video_ref()
    priority_list = []
    for row in matrix:
        priority = row[6]
        if priority in priority_list:
            continue
        else:
            priority_list.append(priority)
    f = (0, 0, 400, 300)
    priority_list.sort()
    result = show_list_dialog(priority_list, frame=f, name='Select Priority')
    dance_priority.text=str(result)
    dance_button.enabled=False
    dance_instructor.text = 'Select Instructor(s)'
    search_dance.text = 'dance name'
    pattern_button.enabled=False
    pattern_video.text = 'dance pattern'
    play_button.enabled=False
    return
#
priority_button = ui.Button(frame=(240,10,130,0),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=priority_action, font=('Arial Rounded MT Bold',18))
priority_button.title='Priority'
priority_button.width=80
priority_button.height=40
view.add_subview(priority_button)

dance_priority_value='0'
dance_priority = ui.TextField(frame=(330,15,130,0),border_color='black', border_width=2, text=dance_priority_value, bordered=True, font=('Arial Rounded MT Bold',15))
dance_priority.height=30
dance_priority.width=30
dance_priority.enabled=False
dance_priority.alignment=ui.ALIGN_CENTER
view.add_subview(dance_priority)

dance_value='dance name'
search_dance = ui.TextField(frame=(100,65,130,0),border_color='black', border_width=2, text=dance_value, bordered=True, font=('Arial Rounded MT Bold',15))
search_dance.height=30
search_dance.width=130
search_dance.enabled=False
view.add_subview(search_dance)

#
def dance_action(sender):
    global dance_matrix
    dance_list = []
    for row in dance_matrix:
        dance = row [1]
        if dance in dance_list:
            continue
        else:
            dance_list.append(dance)
    f = (0, 0, 400, 300)
    try:
        result = show_list_dialog(dance_list, frame=f, name='Select a Dance')
        search_dance.text=result
        new_matrix = []
        for row in dance_matrix:
            if row[1] == search_dance.text:
                new_matrix.append(row)
        dance_matrix = new_matrix
        pattern_button.enabled=True
    except:
        search_dance.text = 'try again'
    return
#
dance_button = ui.Button(frame=(10,60,130,30),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=dance_action, font=('Arial Rounded MT Bold',18))
dance_button.title='Dance'
dance_button.width=80
dance_button.height=40
dance_button.enabled=False
view.add_subview(dance_button)

#
pattern_value='dance pattern'
pattern_video = ui.TextView(frame=(100,105,80,0),border_color='black', border_width=2, text=pattern_value, bordered=True, font=('Arial Rounded MT Bold',15))
pattern_video.height=65
pattern_video.width=260
pattern_video.enabled=False
view.add_subview(pattern_video)
#
def pattern_action(sender):
    global found_row
    global dance_matrix
    pattern_list = []
    for row in dance_matrix:
        if row[4] in pattern_list:
            continue
        else:
            pattern_list.append(row[4])
    f = (0, 0, 400, 300)
    result = show_list_dialog(pattern_list, frame=f, name='Select a Pattern')

    found=False
    for row in dance_matrix:
        if row[4] == result:
            found_row = row
            found=True
            break
    if found:
        pattern_video.text=found_row[3]
        dance_instructor.text = found_row[2]
        play_button.enabled=True
    else:
        pattern_video.text='none found'
    dance_button.enabled=False
    return
#
pattern_button = ui.Button(frame=(10,120,130,30),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=pattern_action, font=('Arial Rounded MT Bold',18))
pattern_button.title='Pattern'
pattern_button.width=80
pattern_button.height=40
pattern_button.enabled=False
view.add_subview(pattern_button)

#
def play_action(sender):
    n = nsurl(found_row[5])
    u=ObjCClass('AVURLAsset'). alloc().initWithURL_options_(n,None)
    i=AVPlayerItem.playerItemWithAsset_(u)
    p=AVPlayer.playerWithPlayerItem_(i)
    videolayer=AVPlayerLayer. playerLayerWithPlayer_(p)

    v=ui.View(frame=(0,0,500,500))
    V=ObjCInstance(v)
    videolayer.frame=V.bounds()
    V.layer().addSublayer_(videolayer)
    v.present('sheet')
    #
    def play_video_action(sender):
        p.play()
        return
    #
    def pause_video_action(sender):
        p.pause()
        return
    #
    def stop_action(sender):
        p.pause()
        seek(0)
        slider.value = 0
        return
    #
    def add_spaces(sender):
        print('space')
        return
    #
    duration_sec = float(found_row[7])
    slider=ui.Slider(frame=(0,0,v.width,110), background_color = 'lightblue')

    @on_main_thread
    def seek(t):
        T=c.CMTimeMakeWithSeconds(t,1)
        p.seekToTime_(T,argtypes=[CMTime], restype=None)
    #
    def slider_action(sender):
        seek(sender.value*duration_sec)
    slider.action=slider_action
    v.add_subview(slider)
    #
    v.left_button_items = (((ui.ButtonItem(title='  ', action= add_spaces))),(ui.ButtonItem(title='\u23F8',action=pause_video_action)), ((ui.ButtonItem(title='  ', action= add_spaces))),((ui.ButtonItem(title='\u25B6', action= play_video_action))), ((ui.ButtonItem(title='  ', action= add_spaces))),((ui.ButtonItem(title='\u23F9', action= stop_action))))
    #
    p.play()

    return

#
play_button = ui.Button(frame=(10,170,130,30),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=play_action, font=('Arial Rounded MT Bold',18))
play_button.title='\u25B6'
play_button.width=80
play_button.height=40
play_button.enabled=False
view.add_subview(play_button)



AVPlayerItem=ObjCClass('AVPlayerItem')
AVPlayer=ObjCClass('AVPlayer')
AVPlayerLayer=ObjCClass('AVPlayerLayer')
import photos

def pick_asset():
       assets = photos.get_assets(media_type='video')
       asset = photos.pick_asset(assets)
       phasset=ObjCInstance(asset)
       asseturl=ObjCClass('AVURLAsset').alloc().initWithURL_options_(phasset.ALAssetURL(),None)
       return asseturl
#define cmtime, for seeking
import ctypes
CMTimeValue=ctypes.c_int64
CMTimeScale=ctypes.c_int32
CMTimeFlags=ctypes.c_uint32
CMTimeEpoch=ctypes.c_int64
class CMTime(Structure):
   _fields_=[('value',CMTimeValue),
   ('timescale',CMTimeScale),
   ('flags',CMTimeFlags),
   ('epoch',CMTimeEpoch)]
   def __init__(self,value=0,timescale=1,flags=0,epoch=0):
      self.value=value
      self.timescale=timescale
      self.flags=flags
      self.epoch=epoch
c.CMTimeMakeWithSeconds.argtypes=[ctypes.c_double,ctypes.c_int32]
c.CMTimeMakeWithSeconds.restype=CMTime
c.CMTimeGetSeconds.argtypes=[CMTime]
c.CMTimeGetSeconds.restype=c_double

############



#########################################
nav_view = ui.NavigationView(view)
nav_view.present('sheet')
#########################################
JonB

I could be wrong, but it may be that the update method is only called at the top level view, the one that you called present on. So you would need to set the update interval on the top level view,and then implement an update in that view to call update in cvp's custom view.

JonB

ProbBly the "right_ way to do this is to implement an objcblock that can be passed to the AVPlayer's
addPeriodicTimeObserver_forInterval_queue_using_.

frankL

JonB, you're over my head on that. If you look at my code, how would I call an update at the top level before the subview is instantiated? And my understanding of objc is very small. I wouldn't know how to implement an objclock to pass to AVPlayer. Suggestions? Thanks.

JonB

Alternatively, edit your post and add the ``` before and after the code.

cvp

@JonB said:

the update method is only called at the top level view

I don't think so, I have ui.Views that I simulate as buttons to play a gif in their image, and def update works perfectly.

JonB

@frankL does your code actually play the video, or that's what you are going for? I don't see the A player getting instantiated, or the sublayer assigned, etc

cvp

@frankL the problem is that to can use update method, you have to use a subclass of ui.View, thus, replace all your play_action function by

class MyView(ui.View):
    def __init__(self, *args, **kwargs):
        global found_row
        ui.View.__init__(self, *args, **kwargs)
        n = nsurl(found_row[5])
        u=ObjCClass('AVURLAsset'). alloc().initWithURL_options_(n,None)
        i=AVPlayerItem.playerItemWithAsset_(u)
        p=AVPlayer.playerWithPlayerItem_(i)
        videolayer=AVPlayerLayer. playerLayerWithPlayer_(p)
        self.p = p
        self.i = i

        self.background_color = 'white'

        V=ObjCInstance(self)
        videolayer.frame=V.bounds()
        V.layer().addSublayer_(videolayer)

        self.update_interval = 0        

        self.left_button_items = (((ui.ButtonItem(title='  ', action= self.add_spaces))),(ui.ButtonItem(title='\u23F8',action=self.pause_video_action)), ((ui.ButtonItem(title='  ', action= self.add_spaces))),((ui.ButtonItem(title='\u25B6', action= self.play_video_action))), ((ui.ButtonItem(title='  ', action= self.add_spaces))),((ui.ButtonItem(title='\u23F9', action= self.stop_action))))

        self.slider=ui.Slider(frame=(0,0,self.width,110), background_color = 'lightblue')
        self.slider.action=self.slider_action
        self.slider.bring_to_front()
        self.add_subview(self.slider)

    def update(self):
        duration=self.i.duration()
        if duration.b == 0:
            return
        self.duration_sec=duration.a/duration.b
        s = self.p.currentTime().a/self.p.currentTime().b
        self.slider.value = s/self.duration_sec

    def play_video_action(self,sender):
        self.p.play()
        return
    #
    def pause_video_action(self,sender):
        self.p.pause()
        return
    #
    def stop_action(self,sender):
        self.p.pause()
        self.seek(0)
        self.slider.value = 0
        return
    #
    def add_spaces(self,sender):
        print('space')
        return

    def slider_action(self, sender):
        self.seek(sender.value*self.duration_sec)

    @on_main_thread
    def seek(self,t):
        T=c.CMTimeMakeWithSeconds(t,1)
        self.p.seekToTime_(T,argtypes=[CMTime],restype=None)

def play_action(sender):
    global p

    v=MyView(frame=(0,0,500,500))
    v.present('sheet')

    v.p.play()
    v.update_interval = 1/60    
frankL

cvp,
I replaced the play_action function with your code and I get an error "name '@on_main_thread' is not defined". I'm relatively new to python and haven't tried to create and use "class" so there must be something else I need to add somewhere. What should I do? Thanks

cvp

@frankL sure that this line is still in the imports...

from objc_util import *
cvp

@frankL I'll be away for 2 hours, sorry. Anyway, if problem still occurs, you can post your code again, included in two lines with ``` (you can use the button to generate them).

cvp

@frankL or if you prefer, I post your full script modified with my little part.

frankL

Apparently I had the 'from objc_util import *' after the class MyView(ui.View):
Once I move it up everything works perfectly. I can't thank you enough.
I retired a few years ago and just started learning Python last summer and Pythonista late last fall so I've got a lot to learn and I really appreciate all of your help and the help from everyone on the omz:forum.

cvp

@frankL 👍

frankL

Thank you for your help. My video player script is now working very well. I still have one other hurdle that I haven’t figured out how to solve and can use some more help. I have created a csv file to hold the url and some other parameters for each video. I use the parameters in my video player script to find the one I want and play it. The way I got the url for each video was very manual and I would like to eliminate the manual step. I used the video picker from the minimal player to select the video from my iphone and print the AVURLAsset to the console which looks like this:

I then click on it in the console and copy it and then paste:

assets-library://asset/asset.mp4? id=40295592-62D9-4521-9DFF-74A5683BF5EB&ext=mp4

to another script as part of a list with the other parameters like this:

Dance = 'Tango'
Instructor = 'Lucy'
description = 'Tango 001-Ronde to swivels'
label = 'Ronde to swivels'
n = nsurl(assets-library://asset/asset.mp4? id=40295592-62D9-4521-9DFF-74A5683BF5EB&ext=mp4')
row = (Dance, Instructor, description, label, n)

to create a row. In order to make this work, I have to paste the url into the n=nsurl(‘ url-goes-here ’) that includes the inner single quote marks.
Once I had several rows, I ran a script to write the csv file which I use as my database for videos.
So back to my question, is there a way to grab the AVURLAsset from the video picker
u=pick_asset()

and somehow extract the url from u, and create the row to append to the csv file?

cvp

@frankL only, when you pick your asset

def pick_asset():
    assets = photos.get_assets(media_type='video')
    asset = photos.pick_asset(assets)
    phasset=ObjCInstance(asset)
    url_str = str(phasset.ALAssetURL()) 

You store this url_str in your csv

And when you use it

    url = nsurl(url_str)
    asseturl=ObjCClass('AVURLAsset').alloc().initWithURL_options_(phasset.ALAssetURL(),None)
frankL

Thank you.