• Purchasing a license grants permission to use the software and to get Tech Support. A license purchase doesn't grant customization support.

Can I use API to upload to particular album(not user)?

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
Hi there everyone!

The bulk importer is not quite robust or feature rich to manage my images uploaded from my phone so I'm hoping to write a script run via cron that will upload to a album titled "Autoupload" that's marked private. I see in the API documentation that I can override the route to upload to a particular user but my gallery is private. I don't need to upload to a particular user but instead, a particular gallery.

Is this possible? If so, what do I need to be modifying to make it happen?

Thanks for your time!
 

Rodolfo

Chevereto Developer
Chevereto Staff
Joined
Oct 7, 2008
Messages
15,526
Points
237
Location
Chevereto HQ
Website
rodolfoberrios.com
The bulk importer is not quite robust or feature rich to manage my images uploaded from my phone
You are talking about "automatic" importing, that's not something that the Bulk importer does. Read the docs here: https://chevereto.com/docs/bulk-importer

Regarding the API, you have to create your own API to achieve what you need. Take examples from route.json.php
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
Regarding the API, you have to create your own API to achieve what you need. Take examples from route.json.php
I see in route.json.php, this bit:

Code:
               // Fix some encoded stuff
                if (!empty($_REQUEST['album_id'])) {
                    $_REQUEST['album_id'] = CHV\decodeID($_REQUEST['album_id']);
                }
Do I simply need to set this var via a modified route.api.php when uploading the files?
 

Rodolfo

Chevereto Developer
Chevereto Staff
Joined
Oct 7, 2008
Messages
15,526
Points
237
Location
Chevereto HQ
Website
rodolfoberrios.com
No, you have to pay attention to the actual CHV\Album methods.

PHP:
CHV\Album::addImages(1, [1,3,4]);
^ Adds images ID 1,2,3 to the album ID 1.
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
Hi there again, sorry for continuing to bother.

My grasp of PHP is not the best and I'm struggling to figure out what exactly I need to change to upload to my Autoupload directory(id in URL is g3R).

In route.json.php, I see on line 933 the function you mentioned above:

Code:
$album_add = CHV\Album::addImages($album_db['album_id'], $images_ids);
Does that mean I need to duplicate this route as an override and modify line 933 in the override file to do what I want?

I've written the script I want to run via cron. I'm not sure if something needs to be done on the script end as well to achieve an upload to my desired album.

Code:
<?php

//***********************************************//
//            Automated image upload               //
//       for Chevereto gallery script            //
//        located at: chevereto.com              //
//                                               //
//                                               //
//***********************************************//

$galleryURL = 'https://site.com/gallery';
$imagesDir     = '/home/site/autoupload/';             // Absolute path to image directory to be scanned. 
$apiKey     = 'key';      // API key can be found in Dashboard / Settings / API
$rightNow     = time();

if(file_exists($imagesDir.'lock.txt')){
    // Process is either already running or ended incorrectly.
    $lockTime = file_get_contents($imagesDir.'lock.txt');
    if($rightNow - $lockTime > 3600){
        // It's been over an hour.  It's safe to give it another shot.
        file_put_contents($imagesDir.'lock.txt', $rightnow);
        $upload = 1;
    }
}else{
    // File doesn't exist.  Proceed.
    file_put_contents($imagesDir.'lock.txt', $rightnow);
    $upload = 1;
}

if(ISSET($upload)){
    
    // Proceed with the gallery insertion.
    $items = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($imagesDir),
        RecursiveIteratorIterator::SELF_FIRST
    );

    foreach($items as $item) {
        if(exif_imagetype($item)){
            
            $file = basename($item);
            // $item represents full path, $file is filename only.
            
            // Upload image
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL,$galleryURL.'/api/1/upload');
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array('key' => $apiKey, 'source' => $item, 'format' => 'json')));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $server_output = curl_exec($ch);
            curl_close ($ch);

            // How did it go?
            if ($server_output != 'OK'){
                echo'Image insertion for '.$file.' failed. Exiting.';
                exit();
            }
            
            // After image is uploaded, delete the file.
            if(!file_exists($item) OR !unlink($item)){
                // Problem with deleting file.
                echo $file.' unable to be deleted. Exiting.';
                exit();
            }
            // We're going to take a slight intermission, so as not to hit the server too hard.
            sleep(5);
        }
    }
}

if(!file_exists($imagesDir.'lock.txt') OR !unlink($imagesDir.'lock.txt')){
    echo'Unable to delete lock file.';
}
UNSET($upload);
?>


I would of course be thrilled with any thoughts or insight concerning the entire script but my goal is to upload to my user's Autoupload album.

Thanks for your time!
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
Hi there Rodolfo,

I've been trying for the day to add a route to the override. I simply copied the hello-world file to route.autoupload.php and while

https://schw.im/gallery/hello-world/?key=***

Gets me a Hello world,

https://schw.im/gallery/autoupload/?key=***

Gets me a 403 forbidden. File permissions are the same for each file.

Like I said, I really did nothing more than copying that file so I could make sure any problems I encountered wasn't caused by what was in the file.

Do I need to do something elsewhere to allow the file to be used?
 

SirMoo

Founder license
Beta tester
Joined
Dec 2, 2013
Messages
350
Points
90
PHP:
$galleryURL = 'https://site.com/gallery';
$imagesDir     = '/home/site/autoupload/';             // Absolute path to image directory to be scanned.
$apiKey     = 'key';      // API key can be found in Dashboard / Settings / API
Did you edit these lines?
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
Hi there Mr. Moo,

As I tried to explain above, I haven't even inserted that code yet into the route. I simply copied the hello-world route, renamed it and am geting a 403 when trying to access it via the URL. This is what route.autoupload.php looks like:

Code:
<?php 
/* Just an example of route extension */ 
$route = function($handler) { 
    die('hello world!'); 
};
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
As an update, I've tried the various things.

I've got two files in override, one being hello-world and the other being autoupload. Both files have the hello-world content in them. Hello-world works while autoupload results in a 403 error.

To rule out file permissions, I renamed autoupload to hello-world and vice versa. If permissions or encoding were causing the problems, then hello-world should stop working while autoupload began to work.

route.hello-world.php continues to work while route.autoupload.php still does not although I've reversed the filenames. This should mean that the file I created is ok, my issue has something to do with adding a new route to the system.

Can someone tell me what I'm doing wrong?
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
I figured out what I was doing wrong. I had to rename my route file as it was hitting a protection in htaccess.

If my album name is Autoupload, should my upload code look like this?

Code:
        foreach($items as $item) {
            if(exif_imagetype($item)){
                
                $file = basename($item);
                // $item represents full path, $file is filename only.
                
                // Upload image
               CHV\Album::addImages('Autoupload' , $item);
                                
                // After image is uploaded, delete the file.
                if(!file_exists($item) OR !unlink($item)){
                    // Problem with deleting file.
                    echo $file.' unable to be deleted. Exiting.';
                    exit();
                }
                // We're going to take a slight intermission, so as not to hit the server too hard.
                sleep(5);
            }
        }
    }
Where $item is the fullpath and filename for the image being uploaded?

Here's my route in it's entirety:

Code:
<?php
/* Just an example of route extension */
$route = function($handler) {
    
    $galleryURL = 'https://site.com/gallery';
    $imagesDir     = '/home/site/autoupload/';             // Absolute path to image directory to be scanned. 
    $apiKey     = '***';      // API key can be found in Dashboard / Settings / API
    $rightNow     = time();
    
    if(file_exists($imagesDir.'lock.txt')){
        // Process is either already running or ended incorrectly.
        $lockTime = file_get_contents($imagesDir.'lock.txt');
        if($rightNow - $lockTime > 3600){
            // It's been over an hour.  It's safe to give it another shot.
            file_put_contents($imagesDir.'lock.txt', $rightNow);
            $upload = 1;
            
        }else{
            
        }
    }else{
        // File doesn't exist.  Proceed.
        file_put_contents($imagesDir.'lock.txt', $rightNow);
        $upload = 1;
        
    }
    
    if(ISSET($upload)){
    
        // Proceed with the gallery insertion.
        $items = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($imagesDir),
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach($items as $item) {
            if(exif_imagetype($item)){
                
                $file = basename($item);
                // $item represents full path, $file is filename only.
                
                // Upload image
                                
                // After image is uploaded, delete the file.
                if(!file_exists($item) OR !unlink($item)){
                    // Problem with deleting file.
                    echo $file.' unable to be deleted. Exiting.';
                    exit();
                }
                // We're going to take a slight intermission, so as not to hit the server too hard.
                sleep(5);
            }
        }
    }

    if(!file_exists($imagesDir.'lock.txt') OR !unlink($imagesDir.'lock.txt')){
        echo'Unable to delete lock file.';
    }
    UNSET($upload);
    
};
And the help provided earlier stated:

Code:
CHV\Album::addImages(1, [1,3,4]);
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
It seems that's not the solution. I get this error when testing an image upload:

Fatal error [100]: Expecting array values, NULL given in CHV\Album::addImages
Triggered in /gallery/app/lib/classes/class.album.php at line 258

Stack trace:
#0 /gallery/app/routes/overrides/route.au.php(43): CHV\Album::addImages(3, SplFileInfo)
#1 /gallery/lib/G/classes/class.handler.php(232): G\Handler->{closure}(G\Handler)
#2 /gallery/lib/G/classes/class.handler.php(132): G\Handler->processRequest()
#3 /gallery/app/loader.php(806): G\Handler->__construct(Array)
#4 /gallery/index.php(20): include_once('/gallery/app/loader.php')
Do I need to provide additional data to addImages or provide it in another format?
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
I ran outside of the 5 min edit window but wanted to explain that I realized I needed to use the album ID # and not the name. My issue remains, however. When I upload, I get the error:

Fatal error [100]: Expecting array values, NULL given in CHV\Album::addImages
Triggered in /gallery/app/lib/classes/class.album.php at line 258

Stack trace:
#0 /gallery/app/routes/overrides/route.au.php(43): CHV\Album::addImages(3, SplFileInfo)
#1 /gallery/lib/G/classes/class.handler.php(232): G\Handler->{closure}(G\Handler)
#2 /gallery/lib/G/classes/class.handler.php(132): G\Handler->processRequest()
#3 /gallery/app/loader.php(806): G\Handler->__construct(Array)
#4 /gallery/index.php(20): include_once('/gallery/app/loader.php')
And the code:

Code:
foreach($items as $item) { 
            if(exif_imagetype($item)){ 
                 
                $file = basename($item); 
                // $item represents full path, $file is filename only. 
                 
                // Upload image 
                CHV\Album::addImages(3 , $item); 
                                 
                // After image is uploaded, delete the file. 
                if(!file_exists($item) OR !unlink($item)){ 
                    // Problem with deleting file. 
                    echo $file.' unable to be deleted. Exiting.'; 
                    exit(); 
                } 
                // We're going to take a slight intermission, so as not to hit the server too hard. 
                sleep(5); 
            } 
        }
 

Rodolfo

Chevereto Developer
Chevereto Staff
Joined
Oct 7, 2008
Messages
15,526
Points
237
Location
Chevereto HQ
Website
rodolfoberrios.com
The system is telling you that the method is expecting an array, but you are providing a string.

Remember this:
No, you have to pay attention to the actual CHV\Album methods.

PHP:
CHV\Album::addImages(1, [1,3,4]);
^ Adds images ID 1,2,3 to the album ID 1.
For that method, first argument is the numeric album id; Second argument is an array containing the image numeric ids.

I'm sorry but you have to pay more attention to your coding. In some previous post you also wanted to use the album name, which is not an argument neither handled by the method that you are calling.

Your procedure won't ever work if your code is messy and you just simply try to put whatever $var you have in handle.

I strongly suggest you that instead of just trying values, to look at the source. By doing that, you won't lost time just trying to imagine what kind of value goes in each argument.

Code:
    public static function addImages($album_id, $ids)
    {

        // $album_id can be null.. Remember the user stream

        if (!is_array($ids) or count($ids) == 0) {
            throw new AlbumException('Expecting array values, '.gettype($values).' given in ' . __METHOD__, 100);
        }

        try {

            // Get the images
            $images = Image::getMultiple($ids, true);

            // Get the albums
            $albums = [];

            foreach ($images as $k => $v) {
                if ($v['album']['id'] and $v['album']['id'] !== $album_id) {
                    $album_k = $v['album']['id'];
                    if (!array_key_exists($album_k, $albums)) {
                        $albums[$album_k] = [];
                    }
                    $albums[$album_k][] = $v['id'];
                }
            }

            $db = DB::getInstance();
            $db->query('UPDATE `'.DB::getTable('images').'` SET `image_album_id`=:image_album_id WHERE `image_id` IN ('.implode(',', $ids).')');
            $db->bind(':image_album_id', $album_id);
            $exec = $db->exec();
            if ($exec and $db->rowCount() > 0) {
                // Update the new album
                if (!is_null($album_id)) {
                    self::updateImageCount($album_id, $db->rowCount());
                }
                // Update the old albums
                if (count($albums) > 0) {
                    $album_query = '';
                    $album_query_tpl = 'UPDATE `'.DB::getTable('albums').'` SET `album_image_count` = GREATEST(`album_image_count` - :counter, 0) WHERE `album_id` = :album_id;';
                    foreach ($albums as $k => $v) {
                        $album_query .= strtr($album_query_tpl, [':counter' => count($v), ':album_id' => $k]);
                    }
                    $db = DB::getInstance();
                    $db->query($album_query);
                    $db->exec();
                }
            }
            return $exec;
        } catch (Exception $e) {
            throw new AlbumException($e->getMessage(), 400);
        }
    }
 

schwim

Network license
License owner
Joined
Jul 18, 2017
Messages
16
Points
51
I'm not trying to write messy code and I'm not just trying to plug vars in. I've struggled for countless hours to understand PHP code written by someone much better at it than I am. I promise you my issues aren't because I'm lazy. I'm trying very hard to solve my own problems. I very much appreciate the assistance you give and I'm not trying to leech off of you or have you do the hard work for me.

I do understand that it says it wants an array but I don't understand what you mean when you say that it expects a numeric ID for the image. Should I be building an array with an incremental id for key and the path/filename for the value?

Code:
array(
    [1] => ['/path/to/img.jpg']
)
Like that?