Forum Archive

How videos add to the camera roll

yutashx

I know how images add to the camera roll,usingphotosandphotos.create_image_asset().
However, I don’t know how videos add to it.
I cannot search anymore.Please teach me!

cvp

@yutashx
I'm really estonished but this script works as I hoped πŸ˜‚

# add a local video file to IOS photos
from objc_util import *
import threading

PHPhotoLibrary = ObjCClass('PHPhotoLibrary')
PHAssetChangeRequest = ObjCClass('PHAssetChangeRequest')

def add_video():
    lib = PHPhotoLibrary.sharedPhotoLibrary()
    url = nsurl('IMG_6294.MOV')         # path to local video file

    def change_block():
        req = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL_(url)

    def perform_changes():
        lib.performChangesAndWait_error_(change_block, None)

    t = threading.Thread(target=perform_changes)
    t.start()
    t.join()

if __name__ == '__main__':
    add_video() 
yutashx

Greaaat!Thanks a lot!πŸ˜†

cvp

@yutashx Is it not what you asked?

yutashx

@cvp I’m sorry. I’m not still used to using this forum. 😞
I resolved the problem thanks to you.
Thank you for giving me a great advice!πŸ˜†

beans

I am new and learning now. This code is very useful because I just wanted to add videos to the camera roll. Additionally, I would like to add the videos to my album. I found that AssetCollection.add_assets(assets) enables this. However, I could not find how get the asset of added video using this code. Any way to get the asset ? It would be great if someone could help.

cvp

@beans try this

# add a local video file to IOS photos album
from objc_util import *
import threading

PHPhotoLibrary = ObjCClass('PHPhotoLibrary')
PHAssetChangeRequest = ObjCClass('PHAssetChangeRequest')
PHAssetCollectionChangeRequest = ObjCClass('PHAssetCollectionChangeRequest')

def add_video():
    lib = PHPhotoLibrary.sharedPhotoLibrary()
    url = nsurl('MesTests/mov_bbb.mp4')         # path to local video file

    def change_block():
        req = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL_(url)
        placeholderForCreatedAsset = req.placeholderForCreatedAsset()

        album = 'my_album'
        albumChangeRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle_(album)
        albumChangeRequest.addAssets_([placeholderForCreatedAsset])


    def perform_changes():
        lib.performChangesAndWait_error_(change_block, None)

    t = threading.Thread(target=perform_changes)
    t.start()
    t.join()

if __name__ == '__main__':
    add_video() 
beans

@cvp : Thank you very much for quick response and useful information. I will try the code on my plan and get back to you.

beans

@cvp I tried the code. I can add the video to specified album. However, the code creates the album every time when adding another video to the album with same name (many 'my_album' are created); can not add the video to existing album. Any information or alternative way ?

cvp

@beans sorry for that, I have only tested once. I'll try in the afternoon Brussels time

cvp

@beans that should be ok, I hope

# add a local video file to IOS photos album
from objc_util import *
import threading

PHPhotoLibrary = ObjCClass('PHPhotoLibrary')
PHAssetChangeRequest = ObjCClass('PHAssetChangeRequest')
PHAssetCollectionChangeRequest = ObjCClass('PHAssetCollectionChangeRequest')
PHAssetCollection = ObjCClass('PHAssetCollection')
PHFetchOptions = ObjCClass('PHFetchOptions').alloc()

def add_video():
    lib = PHPhotoLibrary.sharedPhotoLibrary()
    url = nsurl('MesTests/mov_bbb.mp4')         # path to local video file

    PHAssetCollectionType = 1           # album
    PHAssetCollectionSubtype = 2    # albumregular
    album = 'my_album'
    NSPredicate = ObjCClass('NSPredicate').predicateWithFormat_argumentArray_("title = %@", [album])
    PHFetchOptions.setPredicate_(NSPredicate)
    # get number of albums with this name
    fetchresult = PHAssetCollection.fetchAssetCollectionsWithType_subtype_options_(PHAssetCollectionType, PHAssetCollectionSubtype, PHFetchOptions)
    n_albums = fetchresult.count()

    def change_block():
        req = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL_(url)
        placeholderForCreatedAsset = req.placeholderForCreatedAsset()

        if n_albums == 0:
            print('create album',album)
            albumChangeRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle_(album)
        else:
            print('existing album',album)
            albumChangeRequest = PHAssetCollectionChangeRequest.changeRequestForAssetCollection_(fetchresult.firstObject())
        print('add video')
        albumChangeRequest.addAssets_([placeholderForCreatedAsset])


    def perform_changes():
        lib.performChangesAndWait_error_(change_block, None)

    t = threading.Thread(target=perform_changes)
    t.start()
    t.join()

if __name__ == '__main__':
    add_video() 
beans

@cvp Thank you very much. The code works as expected. Very helpful. Additionally I found another issue through testing the code: the file should be accessible as internal file, the file is only stored in iCloud Drive (not imported to the device as accessible) can not be added. I assume this is reasonable but if any way to start importing from iCloud Drive to the device by the code it will be further helpful. Any ideas ? Sorry for repeated asking.

cvp

@beans said:

the file is only stored in iCloud Drive

In which folder? Try to open it as "external folder" in Pythonista files browser

cvp

@beans Once you have defined your iCloud Drive folder as external folder in Pythonista, you can get a file with

    url = nsurl('/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/MyFolder/mov_bbb.mp4')
beans

@cvp I opened that iCloud folder from EXTERNAL FILES. The folder is shown in EXTERNAL FILES. The files existed in the folder are accessible as '/private/var...', however, the files newly added to that folder are not shown in the folder of EXTERNAL FILES and are not accessible as '/private/var...' The newly added files can be shown using os.listdir('/private/var...'). The file names are shown as '.filename.icloud' (they are not shown in the folder of EXTERNAL FILES). I assume the files are not imported to the device or not synced with EXTERNAL FILES and would like to know if any way to import the files by the code.

cvp

@beans it is a known problem: a file not yet locally downloaded is not accessible 😒
If you first download it in the Files app, you should be able to access it.
I think there are some topics in this forum about this problem.
Sorry for you

beans

@cvp Thank you for the information. Anyway, the code is very useful.

henryaukc

yeah. it works