• 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
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!
 

schwim

Network license
License owner
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
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
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
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
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
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
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
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
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
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
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
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?
 

schubert24

Network license
License owner
Hi schwim

I need an autoimporter too and I will definitively have to solve the problem (I know php quite well). What is the current status of your autoupload?

Instead of hacking the php stuff I think about an automated solution by proper HTTP requests using the bulk importer......
BTW: I haven't read anything about image metadata (json) when using the API, but the bulk loader slurps in some json.

My Setup is:
Domain/Website/Database: @a_hoster
Big Data hosted @server_at_home, same Database.
Using the FTP external storage works perfectly as I can access my server directories @home directly.
My pictures aren't uploaded individually. I generate them bulkwise as they are screenshots.

Any info appreciated.


Best regards

Markus
 

schwim

Network license
License owner
Hi there, Markus, and thanks for the post!

I was unfortunately unable to proceed any further due to both my lack of knowledge and the combination of ridicule and utter silence when asking for help here on the forum. I would love to follow your progress, however if you decide to make this feature. In my opinion, it's a large part of what makes a web gallery useful.

If there's any info I can provide, please just let me know. I very seriously doubt that my code would be of any use to you but I'd be happy to help if I can in any way.

Thanks!
Jason
 

schubert24

Network license
License owner
Hi Jason

Well, I personally am verrry happy that I found chevereto just in time. The alternative would have been to write it by myself ;-)

I spent a lot time with joomla but the code and speed is a mess and there are not many alternatives around.
What looks promising to me is the fact that chevereto comes with a complete app framework which looks nice.

The code makes a "best practise" and very professional impression to me so I decided to proceed with chevereto for the near future. We'll see...

I'll write the remote controller now cor chevereto and will let you know when it's ready.

Best regards

Markus
 

schubert24

Network license
License owner
Hi all

I wrote a batch bot for chevereto, basically to schedule jobs like bulk upload from the outside without interaction.
There is no need to hack any chevereto source.

It's a little php website automation bot which makes use of the cool internal json interface of chevereto.

Installation:

1. Unzip the chevereto_bot.zip (attached)
2. Edit the ini/chevereto.ini to your needs
3. run chevereto_bot.php

It does the following:
1. Login to your chevereto instance
2. Scan the dir, given in import_path_local= for dirs of images and jsons to import
3. Create import jobs and run them
4. Housekeeping: deletes old import tasks and cleans orphaned logs

Should be easy to extend as its based on some cool php frameworks.

Let me know what you think if you tried it. Have fun!

Markus
 

Attachments

Top