commit
9255e199a0
@ -5,7 +5,7 @@
|
||||
![Lychee](http://l.electerious.com/uploads/big/c4b58cb87d95aeaed78fdca581cc908c.jpg)
|
||||
![Lychee](http://l.electerious.com/uploads/big/075ac5de5b5d6c593acbb700f0e1d739.jpg)
|
||||
|
||||
Lychee is a free photo-management tool, which runs on your server or web-space. Installing is a matter of seconds. Upload, manage and share photos like from a native application. Lychee comes with everything you need and all your photos are stored securely. Try the [Live Demo](http://electerious.com/lychee_demo/) or read more on our [Website](http://lychee.electerious.com).
|
||||
Lychee is a free photo-management tool, which runs on your server or web-space. Installing is a matter of seconds. Upload, manage and share photos like from a native application. Lychee comes with everything you need and all your photos are stored securely. Try the [Live Demo](http://ld.electerious.com) or read more on our [Website](http://lychee.electerious.com).
|
||||
|
||||
## Installation
|
||||
|
||||
@ -73,4 +73,4 @@ Take a look at the [FAQ](docs/FAQ.md) if you have problems. Discovered a bug? Pl
|
||||
|
||||
## Donate
|
||||
|
||||
I am working hard on continuously developing and maintaining Lychee. Please consider making a donation via [Flattr](https://flattr.com/submit/auto?user_id=electerious&url=http%3A%2F%2Flychee.electerious.com&title=Lychee&category=software) or PayPal (from [our site](http://lychee.electerious.com/)) to keep the project going strong and me motivated.
|
||||
I am working hard on continuously developing and maintaining Lychee. Please consider making a donation via [Flattr](https://flattr.com/submit/auto?user_id=electerious&url=http%3A%2F%2Flychee.electerious.com&title=Lychee&category=software) or PayPal (from [our site](http://lychee.electerious.com/)) to keep the project going strong and me motivated.
|
||||
|
0
dist/main.css
vendored
Executable file → Normal file
0
dist/main.css
vendored
Executable file → Normal file
BIN
dist/main.js
vendored
BIN
dist/main.js
vendored
Binary file not shown.
BIN
dist/view.js
vendored
BIN
dist/view.js
vendored
Binary file not shown.
@ -1,3 +1,22 @@
|
||||
## v3.1.4
|
||||
|
||||
Released August 28, 2016
|
||||
|
||||
- `Fixed` Search stopped working because of an undefined index error (#605)
|
||||
- `Fixed` Better next/previous photo check to prevent an error when opening an album with only one photo
|
||||
|
||||
## v3.1.3
|
||||
|
||||
Released August 22, 2016
|
||||
|
||||
- `Improved` rotate and flip images with GD based on EXIF orientation (Thanks @qligier, #600)
|
||||
- `Improved` enter/leave fullscreen-mode by (not) moving the mouse for one second (Thanks @hrniels, #583)
|
||||
- `Improved` Prefetch the medium photo instead of the big one (Thanks @Bramas, #446)
|
||||
- `Improved` Added "session" to required extensions (#579)
|
||||
- `Improved` Added warning if Imagick is not installed/enabled (Thanks @hrniels, #590)
|
||||
- `Fixed` Don't assume that gd_info exists when running diagnostics (Thanks @hrniels, #589 #565)
|
||||
- `Fixed` Sidebar showing up in smart albums when navigating back from the photo-view
|
||||
|
||||
## v3.1.2
|
||||
|
||||
Released June 12, 2016
|
||||
|
@ -1,41 +0,0 @@
|
||||
### Installation using Docker
|
||||
|
||||
*Note: pre-installation of the latest version of [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and [Docker](https://docs.docker.com/installation/) is required to deploy Lychee using Docker.*
|
||||
|
||||
First, clone the latest version of Lychee and build it using the Dockerfile included in the repository.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/electerious/Lychee.git
|
||||
cd Lychee
|
||||
docker build -t lychee .
|
||||
```
|
||||
|
||||
Once this is finished, remember to set the proper permissions on the `uploads` and `data` directories, so the container can mount these directories as volumes.
|
||||
|
||||
```
|
||||
chmod -R 777 uploads/ data/
|
||||
```
|
||||
|
||||
Now you can use the `docker run` command to run your Lychee container.
|
||||
|
||||
```bash
|
||||
docker run -v /var/lib/mysql --name lychee_data \
|
||||
-v $(pwd)/data:/app/data \
|
||||
-v $(pwd)/uploads:/app/uploads \
|
||||
-i -t -d -p 8000:80 lychee
|
||||
```
|
||||
|
||||
Browse to [localhost:8000](http://localhost:8000/) (the port can be specified via the `-p` flag) and you will see Lychee's configuration page. The default database username is `root` with no password (you can manage MySQL users by running `docker exec -i -t <container_id> mysql`). After submitting your database configuration, you can sign in and create a new username and password and start using Lychee.
|
||||
|
||||
*Note: if you are deploying on a server, you might want to forward your container to port `80` instead of `8000` so it'll be publicly accessible.*
|
||||
|
||||
### Managing Data
|
||||
|
||||
Running the container with the options above mounts three Docker [data volumes](https://docs.docker.com/userguide/dockervolumes/). The first is a named "data" volume used to store the MySQL database. The last two will mount the `/data` and `/uploads` from the container to your host `Lychee` directory. If you would like to upgrade or redeploy Lychee while preserving your data, you can kill the container and the volumes will persist. Just rebuild your new container and run it using a similar command:
|
||||
|
||||
```bash
|
||||
sudo docker run --volumes-from lychee_data \
|
||||
-v $(pwd)/data:/app/data \
|
||||
-v $(pwd)/uploads:/app/uploads \
|
||||
-i -t -d -p 8000:80 lychee
|
||||
```
|
@ -3,7 +3,7 @@ Everything you need is a web-server with PHP 5.5 or later and a MySQL-Database.
|
||||
|
||||
The following PHP extensions must be activated:
|
||||
|
||||
exif, gd, json, mbstring, mysqli, zip
|
||||
session, exif, mbstring, gd, mysqli, json, zip
|
||||
|
||||
To use Lychee without restrictions, we recommend to increase the values of the following properties in `php.ini`:
|
||||
|
||||
|
@ -99,22 +99,22 @@ final class Album {
|
||||
|
||||
case 'f':
|
||||
$return['public'] = '0';
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE star = 1 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url, medium FROM ? WHERE star = 1 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
$return['public'] = '0';
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE public = 1 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url, medium FROM ? WHERE public = 1 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
$return['public'] = '0';
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url, medium FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case '0':
|
||||
$return['public'] = '0';
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = 0 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url, medium FROM ? WHERE album = 0 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -122,7 +122,7 @@ final class Album {
|
||||
$albums = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
$return = $albums->fetch_assoc();
|
||||
$return = Album::prepareData($return);
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = '?' " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url, medium FROM ? WHERE album = '?' " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -554,8 +554,7 @@ final class Photo {
|
||||
|
||||
case 2:
|
||||
// mirror
|
||||
// not yet implemented
|
||||
return false;
|
||||
imageflip($sourceImg, IMG_FLIP_HORIZONTAL);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
@ -564,14 +563,16 @@ final class Photo {
|
||||
|
||||
case 4:
|
||||
// rotate 180 and mirror
|
||||
// not yet implemented
|
||||
return false;
|
||||
imageflip($sourceImg, IMG_FLIP_VERTICAL);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
// rotate 90 and mirror
|
||||
// not yet implemented
|
||||
return false;
|
||||
$sourceImg = imagerotate($sourceImg, -90, 0);
|
||||
$newWidth = $info['height'];
|
||||
$newHeight = $info['width'];
|
||||
$swapSize = true;
|
||||
imageflip($sourceImg, IMG_FLIP_HORIZONTAL);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
@ -583,8 +584,11 @@ final class Photo {
|
||||
|
||||
case 7:
|
||||
// rotate -90 and mirror
|
||||
// not yet implemented
|
||||
return false;
|
||||
$sourceImg = imagerotate($sourceImg, 90, 0);
|
||||
$newWidth = $info['height'];
|
||||
$newHeight = $info['width'];
|
||||
$swapSize = true;
|
||||
imageflip($sourceImg, IMG_FLIP_HORIZONTAL);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
@ -634,7 +638,7 @@ final class Photo {
|
||||
public static function prepareData(array $data) {
|
||||
|
||||
// Excepts the following:
|
||||
// (array) $data = ['id', 'title', 'tags', 'public', 'star', 'album', 'thumbUrl', 'takestamp', 'url']
|
||||
// (array) $data = ['id', 'title', 'tags', 'public', 'star', 'album', 'thumbUrl', 'takestamp', 'url', 'medium']
|
||||
|
||||
// Init
|
||||
$photo = null;
|
||||
@ -647,7 +651,11 @@ final class Photo {
|
||||
$photo['star'] = $data['star'];
|
||||
$photo['album'] = $data['album'];
|
||||
|
||||
// Parse urls
|
||||
// Parse medium
|
||||
if ($data['medium']==='1') $photo['medium'] = LYCHEE_URL_UPLOADS_MEDIUM . $data['url'];
|
||||
else $photo['medium'] = '';
|
||||
|
||||
// Parse paths
|
||||
$photo['thumbUrl'] = LYCHEE_URL_UPLOADS_THUMB . $data['thumbUrl'];
|
||||
$photo['url'] = LYCHEE_URL_UPLOADS_BIG . $data['url'];
|
||||
|
||||
@ -1304,4 +1312,4 @@ final class Photo {
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -21,7 +21,7 @@ function search($term) {
|
||||
* Photos
|
||||
*/
|
||||
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE title LIKE '%?%' OR description LIKE '%?%' OR tags LIKE '%?%'", array(LYCHEE_TABLE_PHOTOS, $term, $term, $term));
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url, medium FROM ? WHERE title LIKE '%?%' OR description LIKE '%?%' OR tags LIKE '%?%'", array(LYCHEE_TABLE_PHOTOS, $term, $term, $term));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
@ -53,10 +53,13 @@ if (hasPermissions(LYCHEE_UPLOADS)===false) $error .= ('Error: \'uploads/
|
||||
if (hasPermissions(LYCHEE_DATA)===false) $error .= ('Error: \'data/\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
|
||||
// About GD
|
||||
$gdVersion = gd_info();
|
||||
if (!$gdVersion['JPEG Support']) $error .= ('Error: PHP gd extension without jpeg support' . PHP_EOL);
|
||||
if (!$gdVersion['PNG Support']) $error .= ('Error: PHP gd extension without png support' . PHP_EOL);
|
||||
if (!$gdVersion['GIF Read Support'] || !$gdVersion['GIF Create Support']) $error .= ('Error: PHP gd extension without full gif support' . PHP_EOL);
|
||||
$gdVersion = array('GD Version' => '-');
|
||||
if (function_exists('gd_info')) {
|
||||
$gdVersion = gd_info();
|
||||
if (!$gdVersion['JPEG Support']) $error .= ('Error: PHP gd extension without jpeg support' . PHP_EOL);
|
||||
if (!$gdVersion['PNG Support']) $error .= ('Error: PHP gd extension without png support' . PHP_EOL);
|
||||
if (!$gdVersion['GIF Read Support'] || !$gdVersion['GIF Create Support']) $error .= ('Error: PHP gd extension without full gif support' . PHP_EOL);
|
||||
}
|
||||
|
||||
// Load config
|
||||
if (!file_exists(LYCHEE_CONFIG_FILE)) exit('Error: Configuration not found. Please install Lychee for additional tests');
|
||||
@ -96,6 +99,10 @@ if (empty(ini_get('allow_url_fopen'))) echo('Warning: You may experience problem
|
||||
// Check mysql version
|
||||
if ($database->server_version<50500) echo('Warning: Lychee uses the GBK charset to avoid sql injections on your MySQL version. Please update to MySQL 5.5 or higher to enable UTF-8 support.' . PHP_EOL);
|
||||
|
||||
// Check imagick
|
||||
if (!extension_loaded('imagick')) echo('Warning: Pictures that are rotated lose their metadata! Please install Imagick to avoid that.' . PHP_EOL);
|
||||
else if (!$settings['imagick']) echo('Warning: Pictures that are rotated lose their metadata! Please enable Imagick in settings to avoid that.' . PHP_EOL);
|
||||
|
||||
// Output
|
||||
if ($error==='') echo('No critical problems found. Lychee should work without problems!' . PHP_EOL);
|
||||
else echo $error;
|
||||
|
2094
src/npm-shrinkwrap.json
generated
2094
src/npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Lychee",
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.4",
|
||||
"description": "Self-hosted photo-management done right.",
|
||||
"authors": "Tobias Reich <tobias@electerious.com>",
|
||||
"license": "MIT",
|
||||
@ -14,20 +14,20 @@
|
||||
"compile": "gulp"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"babel-preset-es2015": "^6.13.2",
|
||||
"basiccontext": "^3.5.1",
|
||||
"basicmodal": "^3.3.5",
|
||||
"basicmodal": "^3.3.7",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-autoprefixer": "3.1.0",
|
||||
"gulp-babel": "^6.1.2",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-inject": "^4.0.0",
|
||||
"gulp-load-plugins": "^1.2.2",
|
||||
"gulp-inject": "^4.1.0",
|
||||
"gulp-load-plugins": "^1.2.4",
|
||||
"gulp-minify-css": "^1.2.4",
|
||||
"gulp-rimraf": "^0.2.0",
|
||||
"gulp-sass": "^2.3.1",
|
||||
"gulp-uglify": "^1.5.3",
|
||||
"jquery": "^2.2.3",
|
||||
"mousetrap": "^1.5.3"
|
||||
"gulp-sass": "^2.3.2",
|
||||
"gulp-uglify": "^2.0.0",
|
||||
"jquery": "^3.1.0",
|
||||
"mousetrap": "^1.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -67,8 +67,6 @@ header.bind = function() {
|
||||
|
||||
header.show = function() {
|
||||
|
||||
clearTimeout($(window).data('timeout'))
|
||||
|
||||
lychee.imageview.removeClass('full')
|
||||
header.dom().removeClass('header--hidden')
|
||||
|
||||
@ -76,18 +74,12 @@ header.show = function() {
|
||||
|
||||
}
|
||||
|
||||
header.hide = function(e, delay = 500) {
|
||||
header.hide = function(e) {
|
||||
|
||||
if (visible.photo() && !visible.sidebar() && !visible.contextMenu() && basicModal.visible()===false) {
|
||||
|
||||
clearTimeout($(window).data('timeout'))
|
||||
|
||||
$(window).data('timeout', setTimeout(function() {
|
||||
|
||||
lychee.imageview.addClass('full')
|
||||
header.dom().addClass('header--hidden')
|
||||
|
||||
}, delay))
|
||||
lychee.imageview.addClass('full')
|
||||
header.dom().addClass('header--hidden')
|
||||
|
||||
return true
|
||||
|
||||
|
@ -80,7 +80,7 @@ $(document).ready(function() {
|
||||
// Fullscreen on mobile
|
||||
.on('touchend', '#imageview #image', function(e) {
|
||||
if (swipe.obj==null || (swipe.offset>=-5&&swipe.offset<=5)) {
|
||||
if (visible.header()) header.hide(e, 0)
|
||||
if (visible.header()) header.hide(e)
|
||||
else header.show()
|
||||
}
|
||||
})
|
||||
|
@ -6,8 +6,8 @@
|
||||
lychee = {
|
||||
|
||||
title : document.title,
|
||||
version : '3.1.2',
|
||||
versionCode : '030102',
|
||||
version : '3.1.4',
|
||||
versionCode : '030104',
|
||||
|
||||
updatePath : '//update.electerious.com/index.json',
|
||||
updateURL : 'https://github.com/electerious/Lychee',
|
||||
@ -185,6 +185,7 @@ lychee.load = function() {
|
||||
|
||||
// Show Album
|
||||
if (visible.photo()) view.photo.hide()
|
||||
if (visible.sidebar() && (albumID==='0' || albumID==='f' || albumID==='s' || albumID==='r')) sidebar.toggle()
|
||||
if (album.json && albumID==album.json.id) view.album.title()
|
||||
else album.load(albumID)
|
||||
|
||||
|
@ -159,7 +159,7 @@ multiselect.resize = function(e) {
|
||||
|
||||
multiselect.stopResize = function() {
|
||||
|
||||
$(document).off('mousemove mouseup')
|
||||
if (multiselect.position.top!==null) $(document).off('mousemove mouseup')
|
||||
|
||||
}
|
||||
|
||||
|
@ -83,9 +83,11 @@ photo.preloadNext = function(photoID) {
|
||||
|
||||
let nextPhoto = album.json.content[photoID].nextPhoto
|
||||
let url = album.json.content[nextPhoto].url
|
||||
let medium = album.json.content[nextPhoto].medium
|
||||
let href = (medium!=null && medium!=='' ? medium : url)
|
||||
|
||||
$('head [data-prefetch]').remove()
|
||||
$('head').append(`<link data-prefetch rel="prefetch" href="${ url }">`)
|
||||
$('head').append(`<link data-prefetch rel="prefetch" href="${ href }">`)
|
||||
|
||||
}
|
||||
|
||||
|
@ -320,7 +320,7 @@ sidebar.createStructure.album = function(data) {
|
||||
|
||||
sidebar.render = function(structure) {
|
||||
|
||||
if (structure==null || structure==='') return false
|
||||
if (structure==null || structure==='' || structure===false) return false
|
||||
|
||||
let html = ''
|
||||
|
||||
|
@ -309,9 +309,12 @@ view.photo = {
|
||||
$('body').css('overflow', 'hidden')
|
||||
|
||||
// Fullscreen
|
||||
$(document)
|
||||
.bind('mouseenter', header.show)
|
||||
.bind('mouseleave', header.hide)
|
||||
var timeout
|
||||
$(document).bind('mousemove', function() {
|
||||
clearTimeout(timeout)
|
||||
header.show()
|
||||
timeout = setTimeout(header.hide, 1000)
|
||||
})
|
||||
|
||||
lychee.animate(lychee.imageview, 'fadeIn')
|
||||
|
||||
@ -329,8 +332,7 @@ view.photo = {
|
||||
|
||||
// Disable Fullscreen
|
||||
$(document)
|
||||
.unbind('mouseenter')
|
||||
.unbind('mouseleave')
|
||||
.unbind('mousemove')
|
||||
|
||||
// Hide Photo
|
||||
lychee.animate(lychee.imageview, 'fadeOut')
|
||||
@ -411,8 +413,8 @@ view.photo = {
|
||||
let $nextArrow = lychee.imageview.find('a#next')
|
||||
let $previousArrow = lychee.imageview.find('a#previous')
|
||||
let photoID = photo.getID()
|
||||
let hasNext = album.json && album.json.content && album.json.content[photoID] && album.json.content[photoID].nextPhoto!==''
|
||||
let hasPrevious = album.json && album.json.content && album.json.content[photoID] && album.json.content[photoID].previousPhoto!==''
|
||||
let hasNext = album.json && album.json.content && album.json.content[photoID] && album.json.content[photoID].nextPhoto!=null && album.json.content[photoID].nextPhoto!==''
|
||||
let hasPrevious = album.json && album.json.content && album.json.content[photoID] && album.json.content[photoID].previousPhoto!=null && album.json.content[photoID].previousPhoto!==''
|
||||
|
||||
if (hasNext===false || lychee.viewMode===true) {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user