omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello β€” I'm @olemoritz on Twitter.


    how to get last video on iphone?

    Pythonista
    3
    41
    7795
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • cvp
      cvp @frankL last edited by

      @frankL said:

      Any insight you can give me would be appreciated

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

      1 Reply Last reply Reply Quote 0
      • frankL
        frankL last edited by ccc

        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')
        #########################################
        
        1 Reply Last reply Reply Quote 0
        • JonB
          JonB last edited by

          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.

          cvp 1 Reply Last reply Reply Quote 0
          • JonB
            JonB last edited by

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

            1 Reply Last reply Reply Quote 0
            • frankL
              frankL last edited by

              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.

              cvp 1 Reply Last reply Reply Quote 0
              • JonB
                JonB last edited by

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

                1 Reply Last reply Reply Quote 0
                • cvp
                  cvp @JonB last edited by

                  @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.

                  1 Reply Last reply Reply Quote 0
                  • JonB
                    JonB last edited by

                    This post is deleted!
                    1 Reply Last reply Reply Quote 0
                    • cvp
                      cvp @frankL last edited by 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	
                      
                      1 Reply Last reply Reply Quote 0
                      • frankL
                        frankL last edited by

                        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 3 Replies Last reply Reply Quote 0
                        • cvp
                          cvp @frankL last edited by

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

                          from objc_util import *
                          
                          1 Reply Last reply Reply Quote 0
                          • cvp
                            cvp @frankL last edited by 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).

                            1 Reply Last reply Reply Quote 0
                            • cvp
                              cvp @frankL last edited by

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

                              1 Reply Last reply Reply Quote 0
                              • frankL
                                frankL last edited by

                                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 1 Reply Last reply Reply Quote 1
                                • cvp
                                  cvp @frankL last edited by

                                  @frankL πŸ‘

                                  1 Reply Last reply Reply Quote 0
                                  • frankL
                                    frankL last edited by

                                    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:

                                    <AVURLAsset: 0x280d73c00, URL = assets-library://asset/asset.mp4? id=40295592-62D9-4521-9DFF-74A5683BF5EB&ext=mp4>

                                    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 1 Reply Last reply Reply Quote 0
                                    • cvp
                                      cvp @frankL last edited by 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)
                                      
                                      1 Reply Last reply Reply Quote 0
                                      • frankL
                                        frankL last edited by

                                        Thank you.

                                        1 Reply Last reply Reply Quote 0
                                        • First post
                                          Last post
                                        Powered by NodeBB Forums | Contributors