Index: /extensions/BatchDownloader/include/BatchDownloader.class.php
===================================================================
--- /extensions/BatchDownloader/include/BatchDownloader.class.php	(revision 23289)
+++ /extensions/BatchDownloader/include/BatchDownloader.class.php	(revision 23290)
@@ -14,6 +14,7 @@
    * @param: string set type ('album'|'tag'|'selection')
    * @param: int set type id (for retrieving album infos for instance)
-   */
-  function __construct($set_id, $images=array(), $type=null, $type_id=null)
+   * @param: string size to download
+   */
+  function __construct($set_id, $images=array(), $type=null, $type_id=null, $size='original')
   {
     global $user, $conf;
@@ -26,4 +27,5 @@
       'type' => null,
       'type_id' => null,
+      'size' => 'original',
       'nb_zip' => 0,
       'last_zip' => 0,
@@ -39,15 +41,5 @@
     {
       $query = '
-SELECT
-    id,
-    user_id,
-    date_creation,
-    type,
-    type_id,
-    nb_zip,
-    last_zip,
-    nb_images,
-    total_size,
-    status
+SELECT *
   FROM '.BATCH_DOWNLOAD_TSETS.'
   WHERE
@@ -95,6 +87,16 @@
     else if ($set_id == 'new')
     {
+      if ($size != 'original')
+      {
+        $type_map = array_keys(ImageStdParams::get_defined_type_map());
+        if (!in_array($size, $type_map))
+        {
+          throw new Exception(sprintf(l10n('Invalid size %s'), $size));
+        }
+      }
+  
       $this->data['type'] = $type;
       $this->data['type_id'] = $type_id;
+      $this->data['size'] = $size;
       
       $query = '
@@ -104,4 +106,5 @@
     type,
     type_id,
+    size,
     nb_zip,
     last_zip,
@@ -115,4 +118,5 @@
     "'.$this->data['type'].'",
     "'.$this->data['type_id'].'",
+    "'.$this->data['size'].'",
     0,
     0,
@@ -255,4 +259,98 @@
   
   /**
+   * get missing derivatives files
+   * @return: array of i.php urls
+   */
+  function getMissingDerivatives($update=false)
+  {
+    if ($this->data['size'] == 'original')
+    {
+      return array();
+    }
+    
+    global $conf;
+    
+    $root_url = get_root_url();
+    $uid = '&b='.time();
+    
+    $params = ImageStdParams::get_by_type($this->data['size']);
+    $last_mod_time = $params->last_mod_time;
+    
+    $image_ids = array_keys($this->images);
+    $to_update = $urls = $inserts = array();
+    
+    $conf['question_mark_in_urls'] = $conf['php_extension_in_urls'] = true;
+    $conf['derivative_url_style'] = 2; //script
+    
+    // images which we need to update stats
+    if ($update)
+    {
+      $query = '
+SELECT image_id, filemtime FROM '.IMAGE_SIZES_TABLE.'
+  WHERE image_id IN('.implode(',', $image_ids).')
+    AND type = "'.$this->data['size'].'"
+;';
+      $registered = array_from_query($query, 'image_id', 'filemtime');
+      
+      $to_update = array_filter($registered, create_function('$t', 'return $t<'.$last_mod_time.';'));
+      $to_update = array_merge($to_update, array_diff($image_ids, $registered));
+    }
+    
+    $query = '
+SELECT id, path, representative_ext, width, height, rotation
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN('.implode(',', $image_ids).')
+  ORDER BY id DESC
+;';
+
+    $result = pwg_query($query);
+    while ($row = pwg_db_fetch_assoc($result))
+    {
+      $src_image = new SrcImage($row);
+      if ($src_image->is_mimetype()) continue;
+      
+      $derivative = new DerivativeImage($this->data['size'], $src_image);
+      // if ($this->data['size'] != $derivative->get_type()) continue;
+      
+      $filemtime = @filemtime($derivative->get_path());
+      
+      if ($filemtime===false || $filemtime<$last_mod_time)
+      {
+        $urls[] = $root_url.$derivative->get_url().$uid;
+      }
+      else if ($update && in_array($row['id'], $to_update))
+      {
+        $imagesize = getimagesize($derivative->get_path());
+        
+        $inserts[ $row['id'] ] = array(
+          'image_id' => $row['id'],
+          'type' => $this->data['size'],
+          'width' => $imagesize[0],
+          'height' => $imagesize[1],
+          'filesize' => filesize($derivative->get_path())/1024,
+          'filemtime' => $filemtime,
+          );
+      }
+    }
+    
+    if (!empty($inserts))
+    {
+      $query = '
+DELETE FROM '.IMAGE_SIZES_TABLE.'
+  WHERE image_id IN('.implode(',', array_keys($inserts)).')
+;';
+      pwg_query($query);
+      
+      mass_inserts(
+        IMAGE_SIZES_TABLE,
+        array('image_id','type','width','height','filesize'),
+        $inserts
+        );
+    }
+    
+    return $urls;
+  }
+  
+  /**
    * deleteLastArchive
    */
@@ -311,13 +409,22 @@
       $query = '
 SELECT
-    id,
-    name,
-    file,
-    path,
-    filesize
+    id, name, file, path,
+    representative_ext, rotation,
+    filesize, width, height
   FROM '.IMAGES_TABLE.'
   WHERE id IN ('.implode(',', $images_to_add).')
 ;';
       $images_to_add = hash_from_query($query, 'id');
+      
+      if ($this->data['size'] != 'original')
+      {
+        $query = '
+SELECT image_id, filesize
+  FROM '.IMAGE_SIZES_TABLE.'
+  WHERE image_id IN ('.implode(',', array_keys($images_to_add)).')
+    AND type = "'.$this->data['size'].'"
+;';
+        $filesizes = simple_hash_from_query($query, 'image_id', 'filesize');
+      }
       
       // open zip
@@ -330,11 +437,23 @@
       $total_size = 0;
       foreach ($images_to_add as $row)
-      {        
-        $zip->addFile(PHPWG_ROOT_PATH . $row['path'], $row['id'].'_'.stripslashes(get_filename_wo_extension($row['file'])).'.'.get_extension($row['path']));
+      {
+        if ($this->data['size'] == 'original')
+        {
+          $zip->addFile(PHPWG_ROOT_PATH . $row['path'], $row['id'].'_'.stripslashes(get_filename_wo_extension($row['file'])).'.'.get_extension($row['path']));
+          $total_size+= $row['filesize'];
+        }
+        else
+        {
+          $src_image = new SrcImage($row);
+          $derivative = new DerivativeImage($this->data['size'], $src_image);
+          $path = $derivative->get_path();
+      
+          $zip->addFile($path, $row['id'].'_'.stripslashes(get_filename_wo_extension(basename($path))).'.'.get_extension($path));
+          $total_size+= $filesizes[ $row['id'] ];
+        }
         
         array_push($images_added, $row['id']);
         $this->images[ $row['id'] ] = $this->data['last_zip'];
         
-        $total_size+= $row['filesize'];
         if ($total_size >= $this->conf['max_size']*1024 and !$force_one_archive) break;
       }
@@ -370,10 +489,10 @@
       
       // over estimed
-      if ( $this->data['status'] == 'done' and $this->data['last_zip'] < $this->data['nb_zip'] )
+      if ($this->data['status'] == 'done')
       {
         $this->updateParam('nb_zip', $this->data['last_zip']);
       }
       // under estimed
-      else if ( $this->data['last_zip'] == $this->data['nb_zip'] and $this->data['status'] != 'done' )
+      else if ($this->data['last_zip'] == $this->data['nb_zip'])
       {
         $this->updateParam('nb_zip', $this->data['last_zip']+1);
@@ -400,9 +519,21 @@
     $image_ids = array_slice(array_keys($this->images), 0, $this->conf['max_elements']);
     
-    $query = '
+    if ($this->data['size'] == 'original')
+    {
+      $query = '
 SELECT SUM(filesize) AS total
   FROM '.IMAGES_TABLE.'
   WHERE id IN ('.implode(',', $image_ids).')
 ;';
+    }
+    else
+    {
+      $query = '
+SELECT SUM(filesize) AS total
+  FROM '.IMAGE_SIZES_TABLE.'
+  WHERE image_id IN ('.implode(',', $image_ids).')
+;';
+    }
+    
     list($total) = pwg_db_fetch_row(pwg_query($query));
     $this->data['estimated_total_size'] = $total;
@@ -416,7 +547,7 @@
   function getEstimatedArchiveNumber()
   {
-    $nb_zip = ceil( $this->getEstimatedTotalSize() / ($this->conf['max_size']*1024) );
-    $this->updateParam('nb_zip', $nb_zip);
-    return $nb_zip;
+    if ($this->data['status'] == 'done') return $this->data['nb_zip'];
+    
+    return ceil( $this->getEstimatedTotalSize() / ($this->conf['max_size']*1024) );
   }
   
@@ -435,5 +566,5 @@
     
     $out = '';
-    for ($i=1; $i<=$this->data['nb_zip']; $i++)
+    for ($i=1; $i<=$this->getEstimatedArchiveNumber(); $i++)
     {
       $out.= '<li id="zip-'.$i.'">';
@@ -482,5 +613,5 @@
     $path.= $set['BASENAME'] . '_';
     $path.= $this->data['user_id'] . $this->data['id'];
-    $path.= $this->data['nb_zip']!=1 ? '_part' . $i : null;
+    $path.= $this->getEstimatedArchiveNumber()!=1 ? '_part' . $i : null;
     $path.= '.zip';
     
@@ -680,11 +811,19 @@
     $set = array(
       'NB_IMAGES' =>     $this->data['nb_images'],
-      'NB_ARCHIVES' =>   $this->data['nb_zip'],
+      'NB_ARCHIVES' =>   $this->data['status']=='new' ? l10n('unknown') : $this->getEstimatedArchiveNumber(),
       'STATUS' =>        $this->data['status'],
       'LAST_ZIP' =>      $this->data['last_zip'],
-      'TOTAL_SIZE' =>    ceil($this->getEstimatedTotalSize()/1024),
-      'LINKS' =>         $this->getDownloadList(BATCH_DOWNLOAD_PUBLIC . 'init_zip'),
+      'TOTAL_SIZE' =>    $this->data['status']=='new' ? l10n('unknown') : ceil($this->getEstimatedTotalSize()/1024),
+      // 'LINKS' =>         $this->getDownloadList(BATCH_DOWNLOAD_PUBLIC . 'init_zip'),
       'DATE_CREATION' => format_date($this->data['date_creation'], true),
+      'SIZE_ID' =>       $this->data['size'],
+      'SIZE' =>          l10n($this->data['size']),
       );
+      
+    if ($this->data['size'] != 'original')
+    {
+      $params = ImageStdParams::get_by_type($this->data['size']);
+      $set['SIZE_INFO'] = $params->sizing->ideal_size[0].' x '.$params->sizing->ideal_size[1];
+    }
     
     return array_merge($set, $this->getNames());
Index: /extensions/BatchDownloader/include/download.inc.php
===================================================================
--- /extensions/BatchDownloader/include/download.inc.php	(revision 23289)
+++ /extensions/BatchDownloader/include/download.inc.php	(revision 23290)
@@ -17,4 +17,5 @@
       $BatchDownloader = new BatchDownloader($_GET['set_id']);
       
+      // delete set
       if ( isset($_GET['cancel']) )
       {
@@ -26,5 +27,6 @@
       }
       
-      if ( isset($_GET['zip']) and $BatchDownloader->getParam('status') != 'done' and $_GET['zip'] > $BatchDownloader->getParam('last_zip') )
+      // prepare next zip
+      if ( isset($_GET['zip']) and $BatchDownloader->getParam('status') != 'new' and $BatchDownloader->getParam('status') != 'done' and $_GET['zip'] > $BatchDownloader->getParam('last_zip') )
       {
         $BatchDownloader->deleteLastArchive();
@@ -32,17 +34,5 @@
       }
       
-      $set = $BatchDownloader->getSetInfo();
-      
-      if (isset($next_file))
-      {
-        $set['U_DOWNLOAD'] = get_root_url().BATCH_DOWNLOAD_PATH . 'download.php?set_id='.$_GET['set_id'].'&amp;zip='.$_GET['zip'];
-        array_push($page['infos'], sprintf(l10n('The archive is downloading, if the download doesn\'t start automatically please <a href="%s">click here</a>'), $set['U_DOWNLOAD']));
-      }
-      
-      if ($BatchDownloader->getParam('status') == 'new' and $BatchDownloader->getParam('nb_images') > 0)
-      {
-        $set['U_EDIT_SET'] = add_url_params(BATCH_DOWNLOAD_PUBLIC . 'view', array('set_id'=>$_GET['set_id']));
-      }
-      
+      // alert limit overflow
       if ($BatchDownloader->getParam('nb_images') > $conf['batch_download']['max_elements'])
       {
@@ -54,6 +44,49 @@
           ));
       }
+      else
+      {
+        if ($BatchDownloader->getParam('status') == 'new')
+        {
+          $missing_derivatives = $BatchDownloader->getMissingDerivatives(true);
+        
+          // generate missing files
+          if (count($missing_derivatives))
+          {
+            $template->assign('missing_derivatives', $missing_derivatives);
+          }
+          // set ready
+          else
+          {
+            $BatchDownloader->updateParam('status', 'ready');
+          }
+        }
+        
+        // display download links
+        if ($BatchDownloader->getParam('status') != 'new')
+        {
+          $template->assign('zip_links', $BatchDownloader->getDownloadList(BATCH_DOWNLOAD_PUBLIC . 'init_zip'));
+        }
+      }
       
-      $set['U_CANCEL'] = add_url_params(BATCH_DOWNLOAD_PUBLIC . 'init_zip', array('set_id'=>$_GET['set_id'], 'cancel'=>'true'));
+      $set = $BatchDownloader->getSetInfo();
+      
+      // link to the zip
+      if (isset($next_file))
+      {
+        $set['U_DOWNLOAD'] = get_root_url().BATCH_DOWNLOAD_PATH . 'download.php?set_id='.$_GET['set_id'].'&amp;zip='.$_GET['zip'];
+        $page['infos'][] = sprintf(l10n('The archive is downloading, if the download doesn\'t start automatically please <a href="%s">click here</a>'), $set['U_DOWNLOAD']);
+      }
+      
+      // link to edit page
+      if ($BatchDownloader->getParam('status') != 'download' and $BatchDownloader->getParam('status') != 'done' and $BatchDownloader->getParam('nb_images') > 0)
+      {
+        $set['U_EDIT_SET'] = add_url_params(BATCH_DOWNLOAD_PUBLIC . 'view', array('set_id'=>$_GET['set_id']));
+      }
+      
+      // cancel link
+      if ($BatchDownloader->getParam('status') != 'done')
+      {
+        $set['U_CANCEL'] = add_url_params(BATCH_DOWNLOAD_PUBLIC . 'init_zip', array('set_id'=>$_GET['set_id'], 'cancel'=>'true'));
+      }
       
       $template->assign(array(
Index: /extensions/BatchDownloader/include/events.inc.php
===================================================================
--- /extensions/BatchDownloader/include/events.inc.php	(revision 23289)
+++ /extensions/BatchDownloader/include/events.inc.php	(revision 23290)
@@ -87,14 +87,13 @@
     if ($set !== false)
     {
-      $BatchDownloader = new BatchDownloader('new', $page['items'], $set['type'], $set['id']);
+      $BatchDownloader = new BatchDownloader('new', $page['items'], $set['type'], $set['id'], $set['size']);
       
       if ($BatchDownloader->getParam('nb_images') != 0)
       {
-        $BatchDownloader->getEstimatedArchiveNumber();
-        
         // if we plan only one zip with less elements than 'max_elements', the download starts immediately
         if (
           $BatchDownloader->getParam('nb_images') <= $conf['batch_download']['max_elements']
-          and $BatchDownloader->getParam('nb_zip') == 1
+          and $BatchDownloader->getParam('size') == 'original'
+          and $BatchDownloader->getEstimatedArchiveNumber() == 1
         )
         {
@@ -133,13 +132,37 @@
   }
   
-  $url = add_url_params($url, array('action'=>'advdown_set'));
+  $url = add_url_params($url, array('action'=>'advdown_set', 'down_size'=>''));
   
   // toolbar button
-  $button = '<script type="text/javascript">var batchdown_count = '.count($page['items']).'; var batchdown_string = "'.l10n('Confirm the download of %d pictures?').'";</script>
-    <li><a href="'. $url .'" title="'.l10n('Download all pictures of this selection').'" class="pwg-state-default pwg-button" rel="nofollow"
-    onClick="return confirm(batchdown_string.replace(\'%d\', batchdown_count));">
-			<span class="pwg-icon batch-downloader-icon" style="background:url(\'' . get_root_url().BATCH_DOWNLOAD_PATH . 'template/zip.png\') center center no-repeat;">&nbsp;</span><span class="pwg-button-text">'.l10n('Download').'</span>
-		</a></li>';
-  $template->concat('PLUGIN_INDEX_ACTIONS', $button);
+  $template->set_filename('batchdwn_button', realpath(BATCH_DOWNLOAD_PATH.'template/download_button.tpl'));
+  $template->assign(array(
+    'BATCH_DOWNLOAD_PATH' => BATCH_DOWNLOAD_PATH,
+    'BATCH_DWN_COUNT' => count($page['items']),
+    'BATCH_DWN_URL' => $url,
+    ));
+    
+  $type_map = ImageStdParams::get_defined_type_map();
+  foreach ($type_map as $params)
+  {
+    $template->append(
+      'BATCH_DOWNLOAD_SIZES',
+      array(
+        'TYPE' => $params->type,
+        'DISPLAY' => l10n($params->type),
+        'SIZE' => $params->sizing->ideal_size[0].' x '.$params->sizing->ideal_size[1],
+        )
+      );
+  }
+  $template->append(
+    'BATCH_DOWNLOAD_SIZES',
+    array(
+      'TYPE' => 'original',
+      'DISPLAY' => l10n('Original'),
+      'SIZE' => null,
+      )
+    );
+    
+  $button = $template->parse('batchdwn_button', true);
+  $template->add_index_button($button, 50);
   $template->concat('COLLECTION_ACTIONS', $button);
 }
Index: /extensions/BatchDownloader/include/functions.inc.php
===================================================================
--- /extensions/BatchDownloader/include/functions.inc.php	(revision 23289)
+++ /extensions/BatchDownloader/include/functions.inc.php	(revision 23290)
@@ -60,14 +60,13 @@
       $batch_id = 0;
       break;
+    default:
+      return false;
   }
   
-  if ( isset($batch_type) and isset($batch_id) )
-  {
-    return array('type'=>$batch_type, 'id'=>$batch_id);
-  }
-  else
-  {
-    return false;
-  }
+  return array(
+    'type' => $batch_type,
+    'id' => $batch_id,
+    'size' => isset($_GET['down_size']) ? $_GET['down_size'] : 'original',
+    );
 }
 
Index: /extensions/BatchDownloader/include/install.inc.php
===================================================================
--- /extensions/BatchDownloader/include/install.inc.php	(revision 23289)
+++ /extensions/BatchDownloader/include/install.inc.php	(revision 23290)
@@ -13,5 +13,5 @@
       'level'           => 0,
       'what'            => array('categories','specials','collections'),
-      'photo_size'      => 'original',
+      'photo_size'      => 'original', // not used
       'archive_prefix'  => 'piwigo',
       'archive_timeout' => 48, /* hours */
@@ -52,13 +52,14 @@
   `user_id` smallint(5) NOT NULL,
   `date_creation` datetime NOT NULL,
-  `type` varchar(16) CHARACTER SET utf8 NOT NULL,
-  `type_id` varchar(64) CHARACTER SET utf8 NOT NULL,
+  `type` varchar(16) NOT NULL,
+  `type_id` varchar(64) NOT NULL,
+  `size` varchar(16) NOT NULL DEFAULT "original",
   `nb_zip` smallint(3) NOT NULL DEFAULT 0,
   `last_zip` smallint(3) NOT NULL DEFAULT 0,
   `nb_images` mediumint(8) NOT NULL DEFAULT 0,
   `total_size` int(10) NOT NULL DEFAULT 0,
-  `status` enum("new","download","done") CHARACTER SET utf8 NOT NULL DEFAULT "new",
+  `status` enum("new","ready","download","done") NOT NULL DEFAULT "new",
   PRIMARY KEY (`id`)
-) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
 ;';
   pwg_query($query);
@@ -70,7 +71,30 @@
   `zip` smallint(5) NOT NULL DEFAULT 0,
   UNIQUE KEY `UNIQUE` (`set_id`,`image_id`)
-) DEFAULT CHARSET=utf8
+) ENGINE=MyISAM DEFAULT CHARSET=utf8
 ;';
   pwg_query($query);
+  
+  $query = '
+CREATE TABLE IF NOT EXISTS `' . $prefixeTable . 'image_sizes` (
+  `image_id` mediumint(8) NOT NULL,
+  `type` varchar(16) NOT NULL,
+  `width` smallint(9) NOT NULL,
+  `height` smallint(9) NOT NULL,
+  `filesize` mediumint(9) NOT NULL,
+  `filemtime` int(16) NOT NULL,
+  PRIMARY KEY (`image_id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8
+;';
+  pwg_query($query);
+  
+  // add a "size" column to download_sets
+  $result = pwg_query('SHOW COLUMNS FROM `' . $prefixeTable . 'download_sets` LIKE "size";');
+  if (!pwg_db_num_rows($result))
+  {      
+    pwg_query('ALTER TABLE `' . $prefixeTable . 'download_sets` ADD `size` varchar(16) NOT NULL DEFAULT "original";');
+  }
+  
+  // add "ready" status
+  pwg_query('ALTER TABLE `' . $prefixeTable . 'download_sets` CHANGE `status` `status` enum("new","ready","download","done") NOT NULL DEFAULT "new";');
 }
 
Index: /extensions/BatchDownloader/main.inc.php
===================================================================
--- /extensions/BatchDownloader/main.inc.php	(revision 23289)
+++ /extensions/BatchDownloader/main.inc.php	(revision 23290)
@@ -17,4 +17,5 @@
 define('BATCH_DOWNLOAD_TSETS',   $prefixeTable . 'download_sets');
 define('BATCH_DOWNLOAD_TIMAGES', $prefixeTable . 'download_sets_images');
+define('IMAGE_SIZES_TABLE',      $prefixeTable . 'image_sizes');
 define('BATCH_DOWNLOAD_LOCAL',   PHPWG_ROOT_PATH . $conf['data_location'] . 'download_archives/');
 define('BATCH_DOWNLOAD_ADMIN',   get_root_url() . 'admin.php?page=plugin-' . BATCH_DOWNLOAD_ID);
Index: /extensions/BatchDownloader/template/download_button.tpl
===================================================================
--- /extensions/BatchDownloader/template/download_button.tpl	(revision 23290)
+++ /extensions/BatchDownloader/template/download_button.tpl	(revision 23290)
@@ -0,0 +1,42 @@
+{footer_script require='jquery'}
+var batchdown_count = {$BATCH_DWN_COUNT};
+var batchdown_string = "{'Confirm the download of %d pictures?'|@translate}";
+{literal}
+jQuery().ready(function() {
+  jQuery("#batchDownloadLink").click(function() {
+	  var elt = jQuery("#batchDownloadBox");
+
+    elt.css("left", Math.min( jQuery(this).offset().left, jQuery(window).width() - elt.outerWidth(true) - 5))
+      .css("top", jQuery(this).offset().top + jQuery(this).outerHeight(true))
+      .toggle();
+
+    return false;
+  });
+
+  jQuery("#batchDownloadBox").on("mouseleave click", function() {
+    jQuery(this).hide();
+  });
+  
+  jQuery("#batchDownloadBox a").click(function() {
+    return confirm(batchdown_string.replace('%d', batchdown_count));
+  });
+});
+{/literal}{/footer_script}
+
+{html_style}{literal}
+.downloadSizeDetails {font-style:italic; font-size:80%;}
+{/literal}{/html_style}
+
+<script type="text/javascript"></script>
+<li><a href="{$BATCH_DWN_URL}" id="batchDownloadLink" title="{'Download all pictures of this selection'|@translate}" class="pwg-state-default pwg-button" rel="nofollow">
+  <span class="pwg-icon batch-downloader-icon" style="background:url('{$ROOT_PATH}{$BATCH_DOWNLOAD_PATH}template/zip.png') center center no-repeat;">&nbsp;</span><span class="pwg-button-text">{'Download'|@translate}</span>
+</a></li>
+
+<div id="batchDownloadBox" class="switchBox" style="display:none">
+  <div class="switchBoxTitle">{'Download'|@translate} - {'Photo sizes'|@translate}</div>
+  {foreach from=$BATCH_DOWNLOAD_SIZES item=size name=loop}{if !$smarty.foreach.loop.first}<br>{/if}
+  <a href="{$BATCH_DWN_URL}{$size.TYPE}" rel="nofollow">
+    {$size.DISPLAY} {if $size.SIZE}<span class="downloadSizeDetails">({$size.SIZE})</span>{/if}
+  </a>
+  {/foreach}
+</div>
Index: /extensions/BatchDownloader/template/init_zip.tpl
===================================================================
--- /extensions/BatchDownloader/template/init_zip.tpl	(revision 23289)
+++ /extensions/BatchDownloader/template/init_zip.tpl	(revision 23290)
@@ -6,4 +6,74 @@
 {/footer_script}
 {/if}
+
+{if $missing_derivatives}
+{combine_script id='jquery.progressBar' load='footer' path='themes/default/js/plugins/jquery.progressbar.min.js'}
+{combine_script id='jquery.ajaxmanager' load='footer' path='themes/default/js/plugins/jquery.ajaxmanager.js'}
+
+{footer_script}
+var derivatives = {ldelim}
+	elements: ["{'","'|@implode:$missing_derivatives}"],
+	done: 0,
+	total: {$missing_derivatives|@count},
+	
+	finished: function() {ldelim}
+		return derivatives.done == derivatives.total;
+	}
+};
+
+function progress(success) {ldelim}
+  jQuery('#progressBar').progressBar(derivatives.done, {ldelim}
+    max: derivatives.total,
+    textFormat: 'fraction',
+    boxImage: '{$ROOT_PATH}themes/default/images/progressbar.gif',
+    barImage: '{$ROOT_PATH}themes/default/images/progressbg_red.gif'
+  });
+  if (success !== undefined) {ldelim}
+		var type = success ? '.regenerateSuccess': '.regenerateError',
+			s = parseInt(jQuery(type).html());
+		jQuery(type).html(++s);
+	}
+}
+
+{literal}
+var queuedManager = jQuery.manageAjax.create('queued', { 
+  queue: true,  
+  cacheResponse: false,
+  maxRequests: 1
+});
+
+function next_derivative() {
+  if (derivatives.finished()) {
+		alert("finish");
+    return;
+	}
+  
+  $("#damn").append(derivatives.elements[ derivatives.done ]+"<br>");
+  
+  jQuery.manageAjax.add("queued", {
+    type: 'GET', 
+    url: derivatives.elements[ derivatives.done ]+'&ajaxload=true', 
+    dataType: 'json',
+    success: function(data) {
+      derivatives.done++;
+      progress(true);
+      next_derivative();
+    },
+    error: function(data) {
+      derivatives.done++;
+      progress(false);
+      next_derivative();
+    }
+  });
+}
+
+$("#begin").click(function() {
+  progress();
+  next_derivative();
+});
+{/literal}{/footer_script}
+
+{/if}
+
 
 {* <!-- Menubar & titrePage --> *}
@@ -32,4 +102,5 @@
     <li class="error">{$elements_error}</li>
     <li><b>{'%d photos'|@translate|@sprintf:$set.NB_IMAGES}</b>{if $set.U_EDIT_SET}, <a href="{$set.U_EDIT_SET}" rel="nofollow">{'Edit the set'|@translate}</a>{/if}</li>
+    <li><b>{'Size'|@translate}:</b> {$set.SIZE} {if $set.SIZE_INFO}<span class="downloadSizeDetails">({$set.SIZE_INFO})</span>{/if}</li>
     <li><b>{'Estimated size'|@translate}:</b> {$set.TOTAL_SIZE} MB</li>
     <li><b>{'Estimated number of archives'|@translate}:</b> {$set.NB_ARCHIVES} <i>({'real number of archives can differ'|@translate})</i></li>
@@ -38,14 +109,34 @@
 </fieldset>
 
+{if $missing_derivatives}
+<fieldset>
+  <legend>Stuff happening</legend>
+  
+  <a id="begin">GO</a>
+  
+  <div id="regenerationMsg" class="bulkAction">
+    <span class="progressBar" id="progressBar"></span>
+  </div>
+  
+  <span class="regenerateSuccess">0</span> -
+  <span class="regenerateError">0</span>
+  
+  <div id="damn">
+  </div>
+</fieldset>
+{/if}
+
+{if $zip_links}
 <fieldset>
   <legend>{'Download links'|@translate}</legend>
   
   <ul class="download-links">
-    {$set.LINKS}
+    {$zip_links}
     <li class="warning">{'<b>Warning:</b> all files will be deleted within %d hours'|@translate|@sprintf:$archive_timeout}</li>
   </ul>
   
-  <a href="{$set.U_CANCEL}" class="cancel-down" onClick="return confirm('{'Are you sure?'|@translate}');">{'Cancel this download'|@translate}</a>
+  {if $set.U_CANCEL}<a href="{$set.U_CANCEL}" class="cancel-down" onClick="return confirm('{'Are you sure?'|@translate}');">{'Cancel this download'|@translate}</a>{/if}
 </fieldset>
+{/if}
 {/if}
 
Index: /extensions/BatchDownloader/template/style.css
===================================================================
--- /extensions/BatchDownloader/template/style.css	(revision 23289)
+++ /extensions/BatchDownloader/template/style.css	(revision 23290)
@@ -38,2 +38,4 @@
     border-color:#f00;
   }
+  
+.downloadSizeDetails {font-style:italic; font-size:80%;}
