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.


    Video as a background

    Pythonista
    3
    18
    4715
    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.
    • RocketBlaster05
      RocketBlaster05 last edited by

      How would I go about setting the background of a scene to a video? Could I download a custom video, import it, then use it as a background, or do I have to set it something like a Webview? Any links/explanations would be appreciated. Thanks!

      cvp 1 Reply Last reply Reply Quote 1
      • cvp
        cvp @RocketBlaster05 last edited by

        @RocketBlaster05 see here

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

          @cvp So I assume this means I won't be able to use a video downloaded onto my iPad? Is the only way to do this with a web view?

          ts 2 Replies Last reply Reply Quote 0
          • ts
            ts @RocketBlaster05 last edited by ts

            @RocketBlaster05 No, you can still do it without a webview. Here’s one I made using my custom AVPlayer class

            import os
            import objc_util
            import time
            
            def is_number(n):
            	if isinstance(n, float) or isinstance(n, int):
            		return True
            	else:
            		return False
            
            def get_playerItem(url):
            	return objc_util.ObjCClass("AVPlayerItem").playerItemWithURL_(objc_util.nsurl(url))
            
            """def log(result):
            	with open("log.txt", "at") as f:
            		f.write(result.__str__())
            		f.write('\n')"""
            
            class AVPlayer:
            	
            	def __init__(self, arg=None, media_type='video'):
            		self.item = None
            		if isinstance(arg, str):
            			self.fp = arg
            			self.item = get_playerItem(arg)
            		self.playCount = 0
            		self.player = objc_util.ObjCClass("AVPlayer").playerWithPlayerItem_(self.item)
            		if self.item:
            			self.load_playerItem()
            			if self.item_load_time:
            				self.first_load()
            		else:
            			self._first_load = False
            		if media_type == 'video':
            			self.layer = objc_util.ObjCClass("AVPlayerLayer").playerLayerWithPlayer_(self.player)
            		elif media_type == 'audio':
            			self.layer = None
            		else:
            			raise ValueError("Media type can only be 'video' or 'audio', where audio files don't need a pre-made AVPlayerLayer")
            	
            	def first_load(self):
            		try:
            			self._kCMTimeZero = self.item.asset().duration()
            			self._kCMTimeZero.a = 0
            			self._kCMTimeZero.b = 1
            			self._kCMTimeZero.c = 1
            			self._kCMTimeZero.d = 0
            			self._first_load = True
            		except AttributeError:
            			pass
            	
            	def load_playerItem(self):
            		try:
            			st = time.time()
            			while not self.item.status():
            				pass
            			self.item_load_time = time.time() - st
            		except AttributeError:
            			pass
            	
            	def player_currentTime(self):
            		return self.player.currentTime().a / self.player.currentTime().b
            	
            	def item_currentTime(self):
            		try:
            			return self.item.currentTime().a / self.item.currentTime().b
            		except AttributeError:
            			return None
            	
            	def item_duration(self):
            		try:
            			temp = self.item.asset().duration()
            			while not temp.b:
            				temp = self.item.asset().duration()
            			if not temp.a:
            				return None
            			return temp.a / temp.b
            		except AttributeError:
            			return None
            
            	def seek(self, val=None, secs=None, prog=None):
            		try:
            			temp = self.item.asset().duration()
            			"""with open("log.txt", "at") as f:
            				f.write("File: {}\nCMTime(value: {}, timescale: {}, flag: {}, epoch: {})\n".format(self.fp, temp.a, temp.b, temp.c, temp.d))"""
            			if is_number(val):
            				ctime = self.item.currentTime()
            				s = (ctime.a / ctime.b) + val
            				temp.a = round(s * temp.b)
            			elif is_number(secs):
            				temp.a = round(secs * temp.b)
            			elif is_number(prog):
            				temp.a = round(temp.a * prog)
            			self.player.seekToTime_toleranceBefore_toleranceAfter_(temp, self._kCMTimeZero, self._kCMTimeZero, argtypes=[objc_util.Structure, objc_util.Structure, objc_util.Structure], restype=None)
            			return True
            		except AttributeError:
            			return False
            	
            	def remove_current_item(self):
            		self.player._removeItem_(self.item)
            	
            	def replace_item(self, arg):
            		if self.item:
            			e = self.item.error()
            			if e:
            				print(self.fp)
            				print(e)
            				print()
            		self.remove_current_item()
            		self.item_load_time = None
            		self.fp = None
            		if isinstance(arg, str):
            			self.fp = arg
            			self.item = get_playerItem(arg)
            		elif arg is not None:
            			raise Exception("replace_item only accepts None or file path in string format")
            			
            		self.playCount = 0
            		self.player.replaceCurrentItemWithPlayerItem_(self.item)
            		if self.item:
            			self.load_playerItem()
            			if self.item_load_time:
            				if not self._first_load:
            					self.first_load()
            

            Now here’s the example I just finished a bit ago using the help that @cvp posted (thank you @cvp and @yueqiw)

            
            import objc_util
            import ui
            import scene
            import os
            from AVPlayer import AVPlayer
            import threading
            import time
            
            refresh_rate = 1 / 60
            sa = objc_util.UIApplication.sharedApplication()
            screen_size = ui.get_screen_size()
            screen_min = min(screen_size)
            screen_max = max(screen_size)
            
            def get_files_by_ext(p, ext):
            	items = []
            	
            	for item in os.listdir(p):
            		item_path = os.path.join(p, item)
            		if os.path.isdir(item_path):
            			for each in get_files_by_ext(item_path, ext):
            				items.append(each)
            		elif os.path.isfile(item_path):
            			if item.rsplit('.', 1)[-1] == ext:
            				items.append(item_path)
            	
            	return items
            
            @objc_util.on_main_thread
            def update_layer():
            	sv.vp.layer.frame = sv.objc_instance.bounds()
            
            def switch_item(val):
            	if sv.v_items_len > 0:
            		sv.i += val
            		while sv.i < 0:
            			sv.i += sv.v_items_len
            		while sv.i >= sv.v_items_len:
            			sv.i -= sv.v_items_len
            		sv.vp.replace_item(sv.v_items[sv.i])
            		v.name = sv.i.__str__()
            		update_layer()
            		sv.vp.player.play()
            	else:
            		print("No item to switch to")
            
            @ui.in_background
            def move_left(sender):
            	switch_item(-1)
            
            @ui.in_background
            def move_right(sender):
            	switch_item(1)
            
            def loop(ref):
            	while v.on_screen:
            		if not ref.vp.player.rate() and not sa.applicationState():
            			ref.vp.seek(secs=0)
            			ref.vp.player.play()
            		time.sleep(refresh_rate)
            	else:
            		ref.vp.remove_current_item()
            
            @ui.in_background
            def setup(ref):
            	if ref.v_items:
            		ref.i = 0
            		v.name = ref.i.__str__()
            		ref.vp = AVPlayer(ref.v_items[ref.i])
            	else:
            		print("There is no file to load")
            		ref.vp = AVPlayer(None)
            	#ref.objc_instance.layer().addSublayer_(ref.vp.layer)
            	ref.objc_instance.layer().insertSublayer_atIndex_(ref.vp.layer, 0)
            	update_layer()
            	ref.vp.player.play()
            	ref.t = threading.Thread(target=loop, args=(ref,))
            	ref.t.start()
            
            class MyScene(scene.Scene):
            	
            	def setup(self):
            		self.update_interval = refresh_rate
            		self.clear_color = objc_util.c.glClearColor
            		self.clear_color.restype = None
            		self.clear_color.argtypes = [objc_util.c_float, objc_util.c_float, objc_util.c_float, objc_util.c_float]
            		self.clear = objc_util.c.glClear
            		self.clear.restype = None
            		self.clear.argtypes = [objc_util.c_uint]
            		self.buffer_bit = 0x00004000
            		self.view.objc_instance.glkView().setOpaque_(False)
            		self.sn = scene.SpriteNode('emj:Christmas_Tree', parent=self)
            		self.sn.position = (0, self.sn.size[1])
            	
            	def draw(self):
            		self.clear_color(0, 0, 0, 0)
            		self.clear(self.buffer_bit)
            	
            	def did_change_size(self):
            		update_layer()
            	
            	def update(self):
            		c = self.children[-1]
            		if sa.statusBarOrientation() == 1:
            			c.position = ((scene.gravity().x + 1) * (0.5 * v.width), c.position.y)
            		else:
            			if sa.statusBarOrientation() == 3:
            				m = -1
            			else: #this is 4
            				m = 1
            			c.position = ((m * scene.gravity().y + 1) * (0.5 * v.width), c.position.y)
            	
            	def touch_began(self, touch):
            		self.children[-1].position = touch.location
            	
            	def touch_moved(self, touch):
            		self.children[-1].position = touch.location
            	
            	def touch_ended(self, touch):
            		self.children[-1].position = touch.location
            
            if __name__ == '__main__':
            	lb = ui.ButtonItem()
            	lb.image = ui.Image('iow:arrow_left_b_32')
            	lb.action = move_left
            	rb = ui.ButtonItem()
            	rb.image = ui.Image('iow:arrow_right_b_32')
            	rb.action = move_right
            	
            	v = ui.View()
            	v.right_button_items = (rb, lb)
            	v.present('fullscreen')
            	
            	sv = scene.SceneView()
            	sv.v_items = get_files_by_ext(".", "mp4")
            	sv.v_items_len = len(sv.v_items)
            	sv.width = v.width
            	sv.height = v.height
            	sv.flex = "WH"
            	sv.scene = MyScene()
            	v.add_subview(sv)
            	setup(sv)
            
            
            RocketBlaster05 1 Reply Last reply Reply Quote 0
            • ts
              ts last edited by

              The first code is saved in a file called AVPlayer.py

              RocketBlaster05 1 Reply Last reply Reply Quote 0
              • RocketBlaster05
                RocketBlaster05 @ts last edited by RocketBlaster05

                @ts Does the first program require a URL to like a youtube video?

                1 Reply Last reply Reply Quote 0
                • RocketBlaster05
                  RocketBlaster05 @ts last edited by

                  def get_playerItem(url):
                  return objc_util.ObjCClass("AVPlayerItem").playerItemWithURL_(objc_util.nsurl(url))

                  And if so Is this line where I put the URL?

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

                    It’s optional, AVPlayer() accepts None or a URL, but yes AVPlayer(url)

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

                      You import AVPlayer from a different file as seen in the second code. That function gets called automatically when you either create a new AVPlayer() or call the replace_item() of the AVPlayer()

                      RocketBlaster05 1 Reply Last reply Reply Quote 0
                      • RocketBlaster05
                        RocketBlaster05 @ts last edited by

                        @ts I Used a YouTube Link in order to test it but it says I have invalid syntax at the question mark in the link (i.e. youtube.com/watch?...) Any Ideas why this is happening? Thanks

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

                          You are going to need the youtube_dl module to get the direct link (not a webpage). If you had local files or a direct link to the media item (video / audio) this would work (pass ‘audio’ as the second argument for AVPlayer() to work with an audio player), otherwise you may have to look into the webview route unless you figure out how to install youtube_dl

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

                            I think if you have downloaded your video in Pythonista files, you could use url like

                            file:///private/var/mobile/Containers/Shared/AppGroup/1B829014-77B3-4446-9B65-034BDDC46F49/Pythonista3/Documents/MesTests/mov_dog.mp4
                            
                            1 Reply Last reply Reply Quote 0
                            • cvp
                              cvp last edited by

                              This works

                              import os
                              import ui
                              
                              v = ui.View()
                              v.frame = (0,0,400,400)
                              web = ui.WebView()
                              v.add_subview(web)
                              movie_path = '~/Documents/MesTests/mov_dog.mp4'
                              mov_url = 'file://' + os.path.expanduser(movie_path)
                              mov_url = mov_url.replace(' ','%20')
                              web.load_url(mov_url)
                              v.present('sheet')
                              
                              1 Reply Last reply Reply Quote 0
                              • ts
                                ts last edited by ts

                                @cvp My introduction is haunting me...I didn’t mean what I said. I said “I made” and then “with the help”, you guys are really kind here and it looks like I just appeared snatching some code and claiming “I made” (I still edit that post to hopefully fix the way I wrote it). Also I’m not trying to ignore you or “be that new guy”, I just wanted to contribute back for all the support here (as a thank you). I guess I deserve that for my quick jump “No here’s my AVPlayer script though”, but instead I should have made my own post to share my code as thanks now I think about it...

                                Also feel free to correct my grammar / code, along with using my code :) I spent nearly if not over 3 years (on and off and many variants of it) updating @JonB take on his avplayer.py (thanks @JonB). I learned from that (originally borrowed his seek method otherwise figured out how it worked) and realized not long ago I don’t actually have to define a CMTime struct in order to seek. The longest and first feat was figuring out how to rotate the video lol...and thirdly obtaining a kCMTimeZero for better precision for seeking after figuring out how to get the seek to work... Also realized since the AVPlayerLooper doesn’t allow a swapTemplateItem method, I just use the standard AVPlayer which works as intended (after a replace item otherwise the AVPlayerLooper freaks out -> requires more replacing). I made the AVPlayer class so I can reuse it, make it better, but more importantly hook it up to work with playlists (once I figure out how to implement that feature). I have lots of ideas; mute audio, add video / audio objects, look into an audio normalizer to save your ears, loopCount, loopBy, and more

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

                                  @ts Don't worry, you can't find worst grammar than mine and even my code is always quick and dirty (my signature 😁). In the forum, for me, if we can help somebody with some lines, it is good. The requester can always make the code better or easier for his personal use.
                                  Welcome here in this marvelous forum, full of marvelous guys using this marvelous app developed by a marvelous super-héro.

                                  1 Reply Last reply Reply Quote 1
                                  • ts
                                    ts last edited by

                                    I entirely agree with your last statement, that is very true (still amazing to this day)

                                    1 Reply Last reply Reply Quote 0
                                    • ts
                                      ts @RocketBlaster05 last edited by ts

                                      @RocketBlaster05 Oh sorry, sometimes I do that. You can take out the .isfile() check in the replace_item() to allow links (I just realized my mistake) and take out the is_int function in the first script (I took out a method that used it but fix is_number() first since that’s the only thing using it). As well take out the “import os” since there is no more, a call to that module. Also that code (first script) can be saved however you want to name it, as well as the class name, but when you want to utilize it, the format is

                                      from file_name import something
                                      

                                      So in my case, the file_name is AVPlayer and I’m importing the class AVPlayer. Also if you run into issues, discuss it somewhere on this forum so I can improve it

                                      The other thing I noticed was in the init(), I did

                                      if type(arg) == str:
                                      

                                      Instead of

                                      if isinstance(arg, str):
                                      

                                      (The difference as I looked it up when I first noticed it is isinstance accepts inheritance whereas type does not)

                                      1 Reply Last reply Reply Quote 0
                                      • ts
                                        ts @RocketBlaster05 last edited by ts

                                        @RocketBlaster05 If you still require the youtube_dl module, you can do it as suggested here or alternatively a small edit I did from his script years ago (in order to get it to work, also, let me know if this code should be removed from this post). Every other week or so, you can backup then download to keep it updated

                                        # coding: utf-8
                                        # author: Shaun Hevey
                                        # youtube-dl downloader is used to download youtube_dl and patch it to work in Pythonista.
                                        # Replace function came from http://stackoverflow.com/questions/39086/search-and-replace-a-line-in-a-file-in-python
                                        # Download file was adapted from Python file downloader (https://gist.github.com/89edf288a15fde45682a)
                                        
                                        import console
                                        import os
                                        import requests
                                        import shutil
                                        import tempfile
                                        import time
                                        import ui
                                        import zipfile
                                        
                                        youtubedl_dir = 'youtube_dl'
                                        youtubedl_location = './site-packages/'
                                        backup_location = './backup/youtube_dl/'
                                        youtubedl_downloadurl = 'https://yt-dl.org/downloads/latest/youtube-dl'
                                        youtubedl_unarchive_location = './temp/'
                                        files_to_change = [('utils.py','import ctypes','#import ctypes'),
                                                           ('utils.py','import pipes','#import pipes'),
                                                           ('YoutubeDL.py','self._err_file.isatty() and ',''),
                                                           ('downloader/common.py','(\'\\r\\x1b[K\' if sys.stderr.isatty() else \'\\r\')','\'\\r\''),
                                                           ('extractor/common.py',' and sys.stderr.isatty()','')]
                                        
                                        def backup_youtubedl(sender):
                                            console.show_activity('Checking for youtube-dl')
                                            if os.path.isdir(youtubedl_location+youtubedl_dir):
                                                console.show_activity('Backing up youtube-dl')
                                                if not os.path.exists(backup_location):
                                                    os.makedirs(backup_location)
                                                shutil.move(youtubedl_location+youtubedl_dir,backup_location+youtubedl_dir+ time.strftime('%Y%m%d%H%M%S'))
                                            console.hide_activity()
                                        
                                        @ui.in_background
                                        def restore_youtubedl_backup(sender):
                                            if not os.path.isdir(backup_location) or not os.listdir(backup_location):
                                                console.alert('Nothing to do', 'No backups found to restore')
                                            else:
                                                folders = os.listdir(backup_location)
                                                folder = folders[len(folders)-1]
                                                shutil.move(backup_location+folder,youtubedl_location+youtubedl_dir)
                                                console.alert('Success','Successfully restored '+folder)
                                        
                                        def downloadfile(url):
                                            localFilename = url.split('/')[-1] or 'download'
                                            with open(localFilename, 'wb') as f:
                                                r = requests.get(url, stream=True)
                                                total_length = r.headers.get('content-length')
                                                if total_length:
                                                    dl = 0
                                                    total_length = float(total_length)
                                                    for chunk in r.iter_content(1024):
                                                        dl += len(chunk)
                                                        f.write(chunk)
                                                        #.setprogress(dl/total_length*100.0)
                                                else:
                                                    f.write(r.content)
                                            return localFilename
                                        
                                        def process_file(path):
                                            os.mkdir(youtubedl_unarchive_location)
                                            if zipfile.is_zipfile(path):
                                                zipfile.ZipFile(path).extractall(path=youtubedl_unarchive_location)
                                        
                                        @ui.in_background
                                        def update_youtubedl(sender):
                                            if os.path.exists(youtubedl_location+youtubedl_dir):
                                                msg = 'Are you sure you want to update youtubedl exists in site-packages and will be overwritten'
                                                if not console.alert('Continue',msg,'OK'):
                                                    return
                                            console.show_activity('Downloading')
                                            file = downloadfile(youtubedl_downloadurl)
                                            console.show_activity('Extracting')
                                            process_file(file)
                                            console.show_activity('Moving')
                                            if os.path.exists(youtubedl_location+youtubedl_dir):
                                                shutil.rmtree(youtubedl_location+youtubedl_dir)
                                            shutil.move(youtubedl_unarchive_location+youtubedl_dir, youtubedl_location)
                                            console.show_activity('Cleaning Up Download Files')
                                            shutil.rmtree(youtubedl_unarchive_location)
                                            os.remove(file)
                                            console.show_activity('Making youtube-dl friendly')
                                            process_youtubedl_for_pythonista()
                                            console.hide_activity()
                                        
                                        def process_youtubedl_for_pythonista():
                                            for patch in files_to_change:
                                                filename, old_str, new_str = patch
                                                replace_in_file(youtubedl_location+youtubedl_dir+'/'+filename, old_str, new_str)
                                        
                                        def replace_in_file(file_path, old_str, new_str):
                                            with open(file_path, encoding='utf-8') as old_file:
                                                #Create temp file
                                                fh, abs_path = tempfile.mkstemp()
                                                os.close(fh)  # close low level and reopen high level
                                                with open(abs_path,'w', encoding='utf-8') as new_file:
                                                    for line in old_file:
                                                        new_file.write(line.replace(old_str, new_str))
                                            #Remove original file
                                            os.remove(file_path)
                                            #Move new file
                                            shutil.move(abs_path, file_path)
                                        
                                        def make_button(title, action):
                                            button = ui.Button(title=title)
                                            button.action = action
                                            button.background_color ='lightgrey'
                                            button.border_color = 'black'
                                            button.border_width = 1
                                            button.flex = 'WB'
                                            return button
                                        
                                        view = ui.View(frame=(0,0,172,132))
                                        view.background_color = 'white'
                                        
                                        backup_button = make_button(title='Backup YoutubeDL', action=backup_youtubedl)
                                        backup_button.center = (view.width * 0.5, view.y+backup_button.height)
                                        view.add_subview(backup_button)
                                        
                                        restore_button = make_button(title='Restore YoutubeDL', action=restore_youtubedl_backup)
                                        restore_button.center = (view.width * 0.5, backup_button.y+restore_button.height*1.75)
                                        view.add_subview(restore_button)
                                        
                                        download_button = make_button(title='Download YoutubeDL', action=update_youtubedl)
                                        download_button.center = (view.width * 0.5, restore_button.y+download_button.height*1.75)
                                        view.add_subview(download_button)
                                        
                                        view.present('sheet')
                                        
                                        1 Reply Last reply Reply Quote 0
                                        • First post
                                          Last post
                                        Powered by NodeBB Forums | Contributors