Merge pull request #92 from electerious/2.1

v2.1
pull/99/head v2.1
Tobias Reich 10 years ago
commit 0f533151db

4
.gitignore vendored

@ -6,7 +6,9 @@ data/config.php
uploads/import/*
uploads/big/*
uploads/thumb/*
plugins/*
!uploads/import/index.html
!uploads/big/index.html
!uploads/thumb/index.html
!uploads/thumb/index.html
!plugins/check.php

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -4,6 +4,7 @@
* @copyright 2014 by Tobias Reich
*/
/* Gradient ------------------------------------------------*/
#content::before {
content: "";
position: absolute;
@ -26,6 +27,7 @@
position: absolute;
padding: 50px 0px 33px 0px;
width: 100%;
min-height: calc(100% - 90px);
-webkit-overflow-scrolling: touch;
}
@ -114,8 +116,11 @@
background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 20%,rgba(0,0,0,0.9) 100%); /* IE10+ */
background: linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 20%,rgba(0,0,0,0.9) 100%); /* W3C */
}
.photo .overlay {
background: rgba(0, 0, 0, .6);
.photo .overlay {
background: -moz-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.5) 80%, rgba(0,0,0,0.9) 100%); /* FF3.6+ */
background: -webkit-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.5) 80%, rgba(0,0,0,0.9) 100%); /* Chrome10+,Safari5.1+ */
background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.5) 80%, rgba(0,0,0,0.9) 100%); /* IE10+ */
background: linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.5) 80%, rgba(0,0,0,0.9) 100%); /* W3C */
opacity: 0;
}
.photo:hover .overlay,

@ -23,8 +23,8 @@
*/
@font-face {
font-family: 'FontAwesome';
src: url('../../font/fontawesome-webfont.eot');
src: url('../../font/fontawesome-webfont.eot?#iefix') format('eot'), url('../../font/fontawesome-webfont.woff') format('woff'), url('../../font/fontawesome-webfont.ttf') format('truetype'), url('../../font/fontawesome-webfont.svg#FontAwesome') format('svg');
src: url('../font/fontawesome-webfont.eot');
src: url('../font/fontawesome-webfont.eot?#iefix') format('eot'), url('../font/fontawesome-webfont.woff') format('woff'), url('../font/fontawesome-webfont.ttf') format('truetype'), url('../font/fontawesome-webfont.svg#FontAwesome') format('svg');
font-weight: normal;
font-style: normal;
}

@ -27,10 +27,6 @@
-moz-transform: translateX(320px);
transform: translateX(320px);
-webkit-user-select: text;
-moz-user-select: text;
user-select: text;
-webkit-transition: -webkit-transform .5s cubic-bezier(.225,.5,.165,1);
-moz-transition: -moz-transform .5s cubic-bezier(.225,.5,.165,1);
transition: transform .5s cubic-bezier(.225,.5,.165,1);
@ -121,6 +117,10 @@
color: #fff;
font-size: 14px;
line-height: 19px;
-webkit-user-select: text;
-moz-user-select: text;
user-select: text;
}
#infobox table tr td:first-child {
width: 110px;
@ -131,10 +131,24 @@
/* Tags ------------------------------------------------*/
#infobox #tags {
margin: 20px 20px 15px 20px;
width: calc(100% - 40px);
margin: 16px 20px 12px 20px;
color: #fff;
display: inline-block;
}
#infobox #tags .empty {
font-size: 14px;
margin-bottom: 8px;
}
#infobox #tags .edit {
display: inline-block;
}
#infobox #tags .empty .edit {
display: inline;
}
#infobox .tag {
float: left;
padding: 4px 7px;
@ -156,7 +170,7 @@
padding: 0px;
margin: 0px 0px -2px 0px;
color: red;
font-size: 12px;
font-size: 11px;
cursor: pointer;
overflow: hidden;
-webkit-transform: scale(0);

File diff suppressed because one or more lines are too long

@ -7,9 +7,6 @@
html,
body {
min-height: 100%;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
body {
background-color: #222;
@ -29,7 +26,15 @@ body.view {
top:50%;
}
* {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-transition: color .3s, opacity .3s ease-out, -webkit-transform .3s ease-out, box-shadow .3s;
-moz-transition: opacity .3s ease-out, -moz-transform .3s ease-out, box-shadow .3s;
transition: color .3s, opacity .3s ease-out, transform .3s ease-out, box-shadow .3s;
}
input {
-webkit-user-select: text !important;
-moz-user-select: text !important;
user-select: text !important;
}

@ -0,0 +1,13 @@
/**
* @name multiselect.css
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
#multiselect {
position: absolute;
background-color: rgba(0, 94, 204, .3);
border: 1px solid rgba(0, 94, 204, 1);
border-radius: 3px;
z-index: 3;
}

@ -46,7 +46,14 @@ album = {
lychee.api(params, function(data) {
if (data==="Warning: Album private!") {
lychee.setMode("view");
if (document.location.hash.replace("#", "").split("/")[1]!=undefined) {
// Display photo only
lychee.setMode("view");
} else {
// Album not public
lychee.content.show();
lychee.goto("");
}
return false;
}
@ -96,46 +103,50 @@ album = {
title = $(".message input.text").val();
if (title==="") title = "Untitled";
if (title.length>0&&title.length<31) {
modal.close();
if (title.length===0) title = "Untitled";
params = "addAlbum&title=" + escape(encodeURI(title));
lychee.api(params, function(data) {
modal.close();
if (data!==false) {
if (data===true) data = 1; // Avoid first album to be true
lychee.goto(data);
} else lychee.error(null, params, data);
params = "addAlbum&title=" + escape(encodeURI(title));
lychee.api(params, function(data) {
});
if (data!==false) {
if (data===true) data = 1; // Avoid first album to be true
lychee.goto(data);
} else lychee.error(null, params, data);
} else loadingBar.show("error", "Title too short or too long. Please try again!");
});
}],
["Cancel", function() {}]
];
modal.show("New Album", "Please enter a title for this album: <input class='text' type='text' placeholder='Title' value='Untitled'>", buttons);
modal.show("New Album", "Enter a title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='Untitled'>", buttons);
},
delete: function(albumID) {
delete: function(albumIDs) {
var params,
buttons,
albumTitle;
if (!albumIDs) return false;
if (albumIDs instanceof Array===false) albumIDs = [albumIDs];
buttons = [
["Delete Album and Photos", function() {
["", function() {
params = "deleteAlbum&albumID=" + albumID;
params = "deleteAlbum&albumIDs=" + albumIDs;
lychee.api(params, function(data) {
if (visible.albums()) {
albums.json.num--;
view.albums.content.delete(albumID);
albumIDs.forEach(function(id, index, array) {
albums.json.num--;
view.albums.content.delete(id);
});
} else lychee.goto("");
if (data!==true) lychee.error(null, params, data);
@ -143,75 +154,93 @@ album = {
});
}],
["Keep Album", function() {}]
["", function() {}]
];
if (albumID==="0") {
if (albumIDs==="0") {
buttons[0][0] = "Clear Unsorted";
modal.show("Clear Unsorted", "Are you sure you want to delete all photos from 'Unsorted'?<br>This action can't be undone!", buttons)
buttons[1][0] = "Keep Unsorted";
} else {
modal.show("Clear Unsorted", "Are you sure you want to delete all photos from 'Unsorted'?<br>This action can't be undone!", buttons);
} else if (albumIDs.length===1) {
buttons[0][0] = "Delete Album and Photos";
buttons[1][0] = "Keep Album";
// Get title
if (album.json) albumTitle = album.json.title;
else if (albums.json) albumTitle = albums.json.content[albumID].title;
else if (albums.json) albumTitle = albums.json.content[albumIDs].title;
modal.show("Delete Album", "Are you sure you want to delete the album '" + albumTitle + "' and all of the photos it contains? This action can't be undone!", buttons);
} else {
buttons[0][0] = "Delete Albums and Photos";
buttons[1][0] = "Keep Albums";
modal.show("Delete Albums", "Are you sure you want to delete all " + albumIDs.length + " selected albums and all of the photos they contain? This action can't be undone!", buttons);
}
},
setTitle: function(albumID) {
setTitle: function(albumIDs) {
var oldTitle = "",
newTitle,
params,
buttons;
if (!albumID) return false;
if (album.json) oldTitle = album.json.title;
else if (albums.json) oldTitle = albums.json.content[albumID].title;
if (!albumIDs) return false;
if (albumIDs instanceof Array===false) albumIDs = [albumIDs];
if (albumIDs.length===1) {
// Get old title if only one album is selected
if (album.json) oldTitle = album.json.title;
else if (albums.json) oldTitle = albums.json.content[albumIDs].title;
oldTitle = oldTitle.replace("'", "&apos;");
}
buttons = [
["Set Title", function() {
newTitle = $(".message input.text").val();
newTitle = ($(".message input.text").val()==="") ? "Untitled" : $(".message input.text").val();
if (newTitle==="") newTitle = "Untitled";
if (visible.album()) {
if (albumID!==""&&albumID!=null&&albumID&&newTitle.length<31) {
album.json.title = newTitle;
view.album.title();
if (visible.album()) {
} else if (visible.albums()) {
album.json.title = newTitle;
view.album.title(oldTitle);
} else if (visible.albums()) {
albums.json.content[albumID].title = newTitle;
view.albums.content.title(albumID);
}
albumIDs.forEach(function(id, index, array) {
albums.json.content[id].title = newTitle;
view.albums.content.title(id);
});
params = "setAlbumTitle&albumID=" + albumID + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) {
}
if (data!==true) lychee.error(null, params, data);
params = "setAlbumTitle&albumIDs=" + albumIDs + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) {
});
if (data!==true) lychee.error(null, params, data);
} else if (newTitle.length>0) loadingBar.show("error", "New title too short or too long. Please try again!");
});
}],
["Cancel", function() {}]
];
modal.show("Set Title", "Please enter a new title for this album: <input class='text' type='text' placeholder='Title' value='" + oldTitle + "'>", buttons);
if (albumIDs.length===1) modal.show("Set Title", "Enter a new title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
else modal.show("Set Titles", "Enter a title for all " + albumIDs.length + " selected album: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
},
setDescription: function(photoID) {
var oldDescription = album.json.description,
var oldDescription = album.json.description.replace("'", "&apos;"),
description,
params,
buttons;
@ -221,26 +250,23 @@ album = {
description = $(".message input.text").val();
if (description.length<800) {
if (visible.album()) {
album.json.description = description;
view.album.description();
}
params = "setAlbumDescription&albumID=" + photoID + "&description=" + escape(description);
lychee.api(params, function(data) {
if (visible.album()) {
album.json.description = description;
view.album.description();
}
if (data!==true) lychee.error(null, params, data);
params = "setAlbumDescription&albumID=" + photoID + "&description=" + escape(description);
lychee.api(params, function(data) {
});
if (data!==true) lychee.error(null, params, data);
} else loadingBar.show("error", "Description too long. Please try again!");
});
}],
["Cancel", function() {}]
];
modal.show("Set Description", "Please enter a description for this album: <input class='text' type='text' placeholder='Description' value='" + oldDescription + "'>", buttons);
modal.show("Set Description", "Please enter a description for this album: <input class='text' type='text' maxlength='800' placeholder='Description' value='" + oldDescription + "'>", buttons);
},
@ -314,4 +340,4 @@ album = {
}
}
};

@ -31,7 +31,7 @@ albums = {
thumb0: data.unsortedThumb0,
thumb1: data.unsortedThumb1,
thumb2: data.unsortedThumb2
}
};
data.starredAlbum = {
id: "f",
@ -41,7 +41,7 @@ albums = {
thumb0: data.starredThumb0,
thumb1: data.starredThumb1,
thumb2: data.starredThumb2
}
};
data.publicAlbum = {
id: "s",
@ -51,7 +51,7 @@ albums = {
thumb0: data.publicThumb0,
thumb1: data.publicThumb1,
thumb2: data.publicThumb2
}
};
albums.json = data;
@ -67,7 +67,7 @@ albums = {
}, waitTime);
})
});
},
@ -85,4 +85,4 @@ albums = {
}
}
};

@ -19,6 +19,12 @@ build = {
},
multiselect: function(top, left) {
return "<div id='multiselect' style='top: " + top + "px; left: " + left + "px;'></div>";
},
album: function(albumJSON) {
if (!albumJSON) return "";
@ -31,7 +37,7 @@ build = {
title = albumJSON.title.substr(0, 18) + "...";
longTitle = albumJSON.title;
}
typeThumb0 = albumJSON.thumb0.split('.').pop();
typeThumb1 = albumJSON.thumb1.split('.').pop();
typeThumb2 = albumJSON.thumb2.split('.').pop();
@ -144,7 +150,7 @@ build = {
modal += "<div class='message center'" + custom_style + ">";
modal += "<h1>" + title + "</h1>";
if (closeButton!=false) {
if (closeButton!==false) {
modal += "<a class='close icon-remove-sign'></a>";
@ -154,7 +160,7 @@ build = {
$.each(button, function(index) {
if (this[0]!="") {
if (this[0]!=="") {
if (index===0) modal += "<a class='button active'>" + this[0] + "</a>";
else modal += "<a class='button'>" + this[0] + "</a>";
@ -235,6 +241,34 @@ build = {
},
tags: function(tags, forView) {
var html = "",
editTagsHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_tags");
if (tags!=="") {
tags = tags.split(",");
tags.forEach(function(tag, index, array) {
html += "<a class='tag'>" + tag + "<span class='icon-remove' data-index='" + index + "'></span></a>";
});
html += editTagsHTML;
} else {
html = "<div class='empty'>No Tags" + editTagsHTML + "</div>";
}
return html;
},
infoboxPhoto: function(photoJSON, forView) {
if (!photoJSON) return "";
@ -266,7 +300,6 @@ build = {
editTitleHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_title");
editDescriptionHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_description");
//["Tags", "<a class='tag'>Abstract<span class='icon-remove'></span></a><a class='tag'>Colors<span class='icon-remove'></span></a><a class='tag'>Photoshop<span class='icon-remove'></span></a><a class='tag'>Something<span class='icon-remove'></span></a><a class='tag'>Lychee<span class='icon-remove'></span></a><a class='tag'>Tags<span class='icon-remove'></span></a><a class='tag icon-plus'></a>"]
infos = [
["", "Basics"],
["Name", photoJSON.title + editTitleHTML],
@ -275,7 +308,8 @@ build = {
["", "Image"],
["Size", photoJSON.size],
["Format", photoJSON.type],
["Resolution", photoJSON.width + " x " + photoJSON.height]
["Resolution", photoJSON.width + " x " + photoJSON.height],
["Tags", build.tags(photoJSON.tags, forView)]
];
if ((photoJSON.takedate+photoJSON.make+photoJSON.model+photoJSON.shutter+photoJSON.aperture+photoJSON.focal+photoJSON.iso)!="") {
@ -300,7 +334,7 @@ build = {
$.each(infos, function(index) {
if (infos[index][1]===""||infos[index][1]==undefined||infos[index][1]==null) infos[index][1] = "-";
if (infos[index][1]===""||infos[index][1]===undefined||infos[index][1]===null) infos[index][1] = "-";
switch (infos[index][0]) {
@ -311,11 +345,11 @@ build = {
break;
case "Tags": // Tags
infobox += "</table>";
infobox += "<div class='separator'><h1>" + infos[index][0] + "</h1></div>";
infobox += "<tr>";
infobox += "<div id='tags'>" + infos[index][1] + "</div>";
infobox += "</tr>";
if (forView!==true&&!lychee.publicMode) {
infobox += "</table>";
infobox += "<div class='separator'><h1>" + infos[index][0] + "</h1></div>";
infobox += "<div id='tags'>" + infos[index][1] + "</div>";
}
break;
default: // Item
@ -392,7 +426,7 @@ build = {
$.each(infos, function(index) {
if (infos[index][1]===""||infos[index][1]==undefined||infos[index][1]==null) infos[index][1] = "-";
if (infos[index][1]===""||infos[index][1]===undefined||infos[index][1]===null) infos[index][1] = "-";
if (infos[index][0]==="") {
@ -419,4 +453,4 @@ build = {
}
}
};

@ -11,26 +11,37 @@ contextMenu = {
show: function(items, mouse_x, mouse_y, orientation) {
if (visible.contextMenu()) contextMenu.close();
contextMenu.close();
$("body")
.css("overflow", "hidden")
.append(build.contextMenu(items));
// Do not leave the screen
if ((mouse_x+$(".contextmenu").outerWidth(true))>$("html").width()) orientation = "left";
if ((mouse_y+$(".contextmenu").outerHeight(true))>$("html").height()) mouse_y -= (mouse_y+$(".contextmenu").outerHeight(true)-$("html").height())
if ((mouse_y+$(".contextmenu").outerHeight(true))>$("html").height()) mouse_y -= (mouse_y+$(".contextmenu").outerHeight(true)-$("html").height());
if (mouse_x>$(document).width()) mouse_x = $(document).width();
if (mouse_x<0) mouse_x = 0;
if (mouse_y>$(document).height()) mouse_y = $(document).height();
if (mouse_y<0) mouse_y = 0;
if (orientation==="left") mouse_x -= $(".contextmenu").outerWidth(true);
if (!mouse_x||!mouse_y) {
mouse_x = "10px";
mouse_y = "10px";
if (mouse_x===null||
mouse_x===undefined||
isNaN(mouse_x)||
mouse_y===null||
mouse_y===undefined||
isNaN(mouse_y)) {
mouse_x = "10px";
mouse_y = "10px";
}
$(".contextmenu").css({
"top": mouse_y,
"left": mouse_x,
"opacity": .98
"opacity": 0.98
});
},
@ -38,11 +49,9 @@ contextMenu = {
add: function(e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
mouse_y = e.pageY - $(document).scrollTop(),
items;
mouse_y -= $(document).scrollTop();
upload.notify();
contextMenu.fns = [
@ -70,24 +79,27 @@ contextMenu = {
settings: function(e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
mouse_y = e.pageY - $(document).scrollTop(),
items;
mouse_y -= $(document).scrollTop();
contextMenu.fns = [
function() { settings.setLogin() },
function() { settings.setSorting() },
function() { window.open(lychee.website,"_newtab"); },
function() { settings.setDropboxKey() },
function() { window.open(lychee.website, "_newtab"); },
function() { window.open("plugins/check.php", "_newtab"); },
function() { lychee.logout() }
];
items = [
["<a class='icon-user'></a> Change Login", 0],
["<a class='icon-sort'></a> Change Sorting", 1],
["<a class='icon-info-sign'></a> About Lychee", 2],
["<a class='icon-folder-open'></a> Set Dropbox", 2],
["separator", -1],
["<a class='icon-info-sign'></a> About Lychee", 3],
["<a class='icon-dashboard'></a> Diagnostics", 4],
["separator", -1],
["<a class='icon-signout'></a> Sign Out", 3]
["<a class='icon-signout'></a> Sign Out", 5]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
@ -97,16 +109,14 @@ contextMenu = {
album: function(albumID, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
mouse_y = e.pageY - $(document).scrollTop(),
items;
if (albumID==="0"||albumID==="f"||albumID==="s") return false;
mouse_y -= $(document).scrollTop();
contextMenu.fns = [
function() { album.setTitle(albumID) },
function() { album.delete(albumID) }
function() { album.setTitle([albumID]) },
function() { album.delete([albumID]) }
];
items = [
@ -120,27 +130,49 @@ contextMenu = {
},
photo: function(photoID, e) {
albumMulti: function(albumIDs, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
mouse_y = e.pageY - $(document).scrollTop(),
items;
mouse_y -= $(document).scrollTop();
multiselect.stopResize();
contextMenu.fns = [
function() { photo.setStar(photoID) },
function() { photo.setTitle(photoID) },
function() { contextMenu.move(photoID, e, "right") },
function() { photo.delete(photoID) }
function() { album.setTitle(albumIDs) },
function() { album.delete(albumIDs) },
];
items = [
["<a class='icon-edit'></a> Rename All", 0],
["<a class='icon-trash'></a> Delete All", 1]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
},
photo: function(photoID, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items;
contextMenu.fns = [
function() { photo.setStar([photoID]) },
function() { photo.editTags([photoID]) },
function() { photo.setTitle([photoID]) },
function() { contextMenu.move([photoID], e, "right") },
function() { photo.delete([photoID]) }
];
items = [
["<a class='icon-star'></a> Star", 0],
["<a class='icon-tags'></a> Tags", 1],
["separator", -1],
["<a class='icon-edit'></a> Rename", 1],
["<a class='icon-folder-open'></a> Move", 2],
["<a class='icon-trash'></a> Delete", 3]
["<a class='icon-edit'></a> Rename", 2],
["<a class='icon-folder-open'></a> Move", 3],
["<a class='icon-trash'></a> Delete", 4]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
@ -149,35 +181,60 @@ contextMenu = {
},
move: function(photoID, e, orientation) {
photoMulti: function(photoIDs, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
mouse_y = e.pageY - $(document).scrollTop(),
items;
multiselect.stopResize();
contextMenu.fns = [
function() { photo.setStar(photoIDs) },
function() { photo.editTags(photoIDs) },
function() { photo.setTitle(photoIDs) },
function() { contextMenu.move(photoIDs, e, "right") },
function() { photo.delete(photoIDs) }
];
items = [
["<a class='icon-star'></a> Star All", 0],
["<a class='icon-tags'></a> Tag All", 1],
["separator", -1],
["<a class='icon-edit'></a> Rename All", 2],
["<a class='icon-folder-open'></a> Move All", 3],
["<a class='icon-trash'></a> Delete All", 4]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
},
move: function(photoIDs, e, orientation) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items = [];
contextMenu.fns = [];
contextMenu.close(true);
if (album.getID()!=="0") {
items = [
["Unsorted", 0, "photo.setAlbum(0, " + photoID + ")"],
["Unsorted", 0, "photo.setAlbum([" + photoIDs + "], 0)"],
["separator", -1]
];
}
lychee.api("getAlbums", function(data) {
if (!data.albums) {
if (data.num===0) {
items = [["New Album", 0, "album.add()"]];
} else {
$.each(data.content, function(index) {
if (this.id!=album.getID()) items.push([this.title, 0, "photo.setAlbum(" + this.id + ", " + photoID + ")"]);
if (this.id!=album.getID()) items.push([this.title, 0, "photo.setAlbum([" + photoIDs + "], " + this.id + ")"]);
});
}
contextMenu.close();
$(".photo[data-id='" + photoID + "']").addClass("active");
if (!visible.photo()) contextMenu.show(items, mouse_x, mouse_y, "right");
else contextMenu.show(items, mouse_x, mouse_y, "left");
@ -201,7 +258,7 @@ contextMenu = {
function() { photo.share(photoID, 3) },
function() { window.open(photo.getDirectLink(),"_newtab") }
];
link = photo.getViewLink(photoID);
if (photo.json.public==="2") link = location.href;
@ -218,7 +275,7 @@ contextMenu = {
];
contextMenu.show(items, mouse_x, mouse_y, "left");
$(".contextmenu input").focus();
$(".contextmenu input").focus().select();
},
@ -253,18 +310,24 @@ contextMenu = {
if (album.json.password==true) items[3] = ["<a class='icon-unlock'></a> Remove Password", 5];
contextMenu.show(items, mouse_x, mouse_y, "left");
$(".contextmenu input").focus();
$(".contextmenu input").focus().select();
},
close: function() {
close: function(leaveSelection) {
if (!visible.contextMenu()) return false;
contextMenu.js = null;
contextMenu.fns = [];
$(".contextmenu_bg, .contextmenu").remove();
$(".photo.active, .album.active").removeClass("active");
$("body").css("overflow", "auto");
if (leaveSelection!==true) {
$(".photo.active, .album.active").removeClass("active");
if (visible.multiselect()) multiselect.close();
}
}
}
};

@ -8,13 +8,17 @@ $(document).ready(function(){
/* Event Name */
var event_name = (mobileBrowser()) ? "touchend" : "click";
/* Disable ContextMenu */
$(document).bind("contextmenu", function(e) { e.preventDefault() });
/* Tooltips */
if (!mobileBrowser()) $(".tools").tipsy({gravity: 'n', fade: false, delayIn: 0, opacity: 1});
/* Multiselect */
$("#content").on("mousedown", multiselect.show);
$(document).on("mouseup", multiselect.getSelection);
/* Header */
$("#hostedwith").on(event_name, function() { window.open(lychee.website,"_newtab") });
$("#button_signin").on(event_name, lychee.loginDialog);
@ -28,21 +32,21 @@ $(document).ready(function(){
else modal.show("Share Album", "All photos inside this album will be public and visible for everyone. Existing public photos will have the same sharing permission as this album. Are your sure you want to share this album? <input class='text' type='password' placeholder='password (optional)' value=''>", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]]);
});
$("#button_download").on(event_name, function() { photo.getArchive(photo.getID()) });
$("#button_trash_album").on(event_name, function() { album.delete(album.getID()) });
$("#button_move").on(event_name, function(e) { contextMenu.move(photo.getID(), e) });
$("#button_trash").on(event_name, function() { photo.delete(photo.getID()) });
$("#button_trash_album").on(event_name, function() { album.delete([album.getID()]) });
$("#button_move").on(event_name, function(e) { contextMenu.move([photo.getID()], e) });
$("#button_trash").on(event_name, function() { photo.delete([photo.getID()]) });
$("#button_info_album").on(event_name, function() { view.infobox.show() });
$("#button_info").on(event_name, function() { view.infobox.show() });
$("#button_archive").on(event_name, function() { album.getArchive(album.getID()) });
$("#button_star").on(event_name, function() { photo.setStar(photo.getID()) });
$("#button_star").on(event_name, function() { photo.setStar([photo.getID()]) });
/* Search */
$("#search").on("keyup click", function() { search.find($(this).val()) });
/* Clear Search */
$("#clearSearch").on(event_name, function () {
$("#search").focus();
search.reset();
$("#clearSearch").on(event_name, function () {
$("#search").focus();
search.reset();
});
/* Back Buttons */
@ -61,16 +65,18 @@ $(document).ready(function(){
/* Infobox */
$("#infobox")
.on(event_name, ".header a", function() { view.infobox.hide() })
.on(event_name, "#edit_title_album", function() { album.setTitle(album.getID()) })
.on(event_name, "#edit_title_album", function() { album.setTitle([album.getID()]) })
.on(event_name, "#edit_description_album", function() { album.setDescription(album.getID()) })
.on(event_name, "#edit_title", function() { photo.setTitle(photo.getID()) })
.on(event_name, "#edit_description", function() { photo.setDescription(photo.getID()) });
.on(event_name, "#edit_title", function() { photo.setTitle([photo.getID()]) })
.on(event_name, "#edit_description", function() { photo.setDescription(photo.getID()) })
.on(event_name, "#edit_tags", function() { photo.editTags([photo.getID()]) })
.on(event_name, "#tags .tag span", function() { photo.deleteTag(photo.getID(), $(this).data('index')) });
/* Keyboard */
Mousetrap
.bind('u', function() { $("#upload_files").click() })
.bind('s', function() { if (visible.photo()) $("#button_star").click() })
.bind('command+backspace', function() { if (visible.photo()&&!visible.message()) photo.delete(photo.getID()) })
.bind('command+backspace', function() { if (visible.photo()&&!visible.message()) photo.delete([photo.getID()]) })
.bind('left', function() { if (visible.photo()) $("#imageview a#previous").click() })
.bind('right', function() { if (visible.photo()) $("#imageview a#next").click() })
.bind('i', function() {
@ -100,18 +106,18 @@ $(document).ready(function(){
/* Header */
.on(event_name, "#title.editable", function() {
if (visible.photo()) photo.setTitle(photo.getID());
else album.setTitle(album.getID());
if (visible.photo()) photo.setTitle([photo.getID()]);
else album.setTitle([album.getID()]);
})
/* Navigation */
.on("click", ".album", function() { lychee.goto($(this).attr("data-id")) })
.on("click", ".photo", function() { lychee.goto(album.getID() + "/" + $(this).attr("data-id")) })
/* Modal */
.on(event_name, ".message .close", modal.close)
.on(event_name, ".message .button:first", function() { if (modal.fns!=null) modal.fns[0](); if (!visible.signin()) modal.close() })
.on(event_name, ".message .button:last", function() { if (modal.fns!=null) modal.fns[1](); if (!visible.signin()) modal.close() })
.on(event_name, ".message .button:first", function() { if (modal.fns!==null) modal.fns[0](); if (!visible.signin()) modal.close() })
.on(event_name, ".message .button:last", function() { if (modal.fns!==null) modal.fns[1](); if (!visible.signin()) modal.close() })
/* Add Dialog */
.on(event_name, ".button_add", function(e) { contextMenu.add(e) })

@ -15,7 +15,7 @@ loadingBar = {
loadingBar.status = "error";
if (!errorText) errorText = "Whoops, it looks like something went wrong. Please reload the site and try again!"
if (!errorText) errorText = "Whoops, it looks like something went wrong. Please reload the site and try again!";
lychee.loadingBar
.removeClass("loading uploading error")
@ -28,7 +28,7 @@ loadingBar = {
clearTimeout(lychee.loadingBar.data("timeout"));
lychee.loadingBar.data("timeout", setTimeout(function() { loadingBar.hide(true) }, 3000));
} else if (loadingBar.status==null) {
} else if (loadingBar.status===null) {
loadingBar.status = "loading";
@ -47,7 +47,7 @@ loadingBar = {
hide: function(force_hide) {
if ((loadingBar.status!=="error"&&loadingBar.status!=null)||force_hide) {
if ((loadingBar.status!=="error"&&loadingBar.status!==null)||force_hide) {
loadingBar.status = null;
clearTimeout(lychee.loadingBar.data("timeout"));
@ -59,4 +59,4 @@ loadingBar = {
}
}
};

@ -7,7 +7,7 @@
var lychee = {
version: "2.0.3",
version: "2.1",
api_path: "php/api.php",
update_path: "http://lychee.electerious.com/version/index.php",
@ -26,6 +26,7 @@ var lychee = {
sorting: "",
dropbox: false,
dropboxKey: '',
loadingBar: $("#loading"),
header: $("header"),
@ -35,13 +36,17 @@ var lychee = {
init: function() {
lychee.api("init", function(data) {
var params;
params = "init&version=" + escape(lychee.version);
lychee.api(params, function(data) {
if (data.loggedIn!==true) {
lychee.setMode("public");
} else {
lychee.username = data.config.username;
lychee.sorting = data.config.sorting;
lychee.username = data.config.username || '';
lychee.sorting = data.config.sorting || '';
lychee.dropboxKey = data.config.dropboxKey || '';
}
// No configuration
@ -68,7 +73,7 @@ var lychee = {
api: function(params, callback, loading) {
if (loading==undefined) loadingBar.show();
if (loading===undefined) loadingBar.show();
$.ajax({
type: "POST",
@ -115,7 +120,7 @@ var lychee = {
localStorage.setItem("username", user);
window.location.reload();
} else {
$("#password").val("").addClass("error");
$("#password").val("").addClass("error").focus();
$(".message .button.active").removeClass("pressed");
}
});
@ -130,7 +135,7 @@ var lychee = {
$("#username").focus();
if (localStorage) {
local_username = localStorage.getItem("username");
if (local_username!=null) {
if (local_username!==null) {
if (local_username.length>0) $("#username").val(local_username);
$("#password").focus();
}
@ -149,7 +154,7 @@ var lychee = {
goto: function(url) {
if (url==undefined) url = "";
if (url===undefined) url = "";
document.location.hash = url;
},
@ -161,6 +166,7 @@ var lychee = {
hash = document.location.hash.replace("#", "").split("/");
contextMenu.close();
multiselect.close();
if (hash[0]!==undefined) albumID = hash[0];
if (hash[1]!==undefined) photoID = hash[1];
@ -255,6 +261,7 @@ var lychee = {
Mousetrap.unbind('esc');
$("#button_back, a#next, a#previous").remove();
$(".no_content").remove();
lychee.publicMode = true;
lychee.viewMode = true;
@ -287,7 +294,7 @@ var lychee = {
loadDropbox: function(callback) {
if (!lychee.dropbox) {
if (!lychee.dropbox&&lychee.dropboxKey) {
loadingBar.show();
@ -298,7 +305,7 @@ var lychee = {
g.id = "dropboxjs";
g.type = "text/javascript";
g.async = "true";
g.setAttribute("data-app-key", "iq7lioj9wu0ieqs");
g.setAttribute("data-app-key", lychee.dropboxKey);
g.onload = g.onreadystatechange = function() {
var rs = this.readyState;
if (rs&&rs!=="complete"&&rs!=="loaded") return;
@ -308,7 +315,15 @@ var lychee = {
};
s.parentNode.insertBefore(g, s);
} else callback();
} else if (lychee.dropbox&&lychee.dropboxKey) {
callback();
} else {
settings.setDropboxKey(callback);
}
},
@ -321,4 +336,4 @@ var lychee = {
}
}
};

File diff suppressed because one or more lines are too long

@ -12,7 +12,7 @@ modal = {
show: function(title, text, buttons, marginTop, closeButton) {
if (!buttons) {
var buttons = [
buttons = [
["", function() {}],
["", function() {}]
];
@ -20,7 +20,7 @@ modal = {
modal.fns = [buttons[0][1], buttons[1][1]];
$("body").append(build.modal(title, text, buttons, marginTop, closeButton));
$(".message input:first-child").focus();
$(".message input:first-child").focus().select();
},
@ -32,4 +32,4 @@ modal = {
}
}
};

@ -1,339 +0,0 @@
/**
* @name Photo Module
* @description Takes care of every action a photo can handle and execute.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
photo = {
json: null,
getID: function() {
var id;
if (photo.json) id = photo.json.id;
else id = $(".photo:hover, .photo.active").attr("data-id");
if (id) return id;
else return false;
},
load: function(photoID, albumID) {
var params,
checkPasswd;
params = "getPhoto&photoID=" + photoID + "&albumID=" + albumID + "&password=" + password.value;
lychee.api(params, function(data) {
if (data==="Warning: Wrong password!") {
checkPasswd = function() {
if (password.value!=="") photo.load(photoID, albumID);
else setTimeout(checkPasswd, 250);
}
checkPasswd();
return false;
}
photo.json = data;
if (!visible.photo()) view.photo.show();
view.photo.init();
lychee.imageview.show();
setTimeout(function() { lychee.content.show() }, 300);
});
},
parse: function() {
if (!photo.json.title) photo.json.title = "Untitled";
photo.json.url = lychee.upload_path_big + photo.json.url;
},
delete: function(photoID) {
var params,
buttons,
photoTitle;
if (!photoID) return false;
if (visible.photo()) photoTitle = photo.json.title;
else photoTitle = album.json.content[photoID].title;
if (photoTitle=="") photoTitle = "Untitled";
buttons = [
["Delete Photo", function() {
// Change reference for the next and previous photo
if (album.json.content[photoID].nextPhoto!==""||album.json.content[photoID].previousPhoto!=="") {
nextPhoto = album.json.content[photoID].nextPhoto;
previousPhoto = album.json.content[photoID].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
album.json.content[photoID] = null;
view.album.content.delete(photoID);
// Only when search is not active
if (!visible.albums()) lychee.goto(album.getID());
params = "deletePhoto&photoID=" + photoID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Keep Photo", function() {}]
];
modal.show("Delete Photo", "Are you sure you want to delete the photo '" + photoTitle + "'?<br>This action can't be undone!", buttons);
},
setTitle: function(photoID) {
var oldTitle = "",
newTitle,
params,
buttons;
if (!photoID) return false;
if (photo.json) oldTitle = photo.json.title;
else if (album.json) oldTitle = album.json.content[photoID].title;
buttons = [
["Set Title", function() {
newTitle = $(".message input.text").val();
if (photoID!=null&&photoID&&newTitle.length<31) {
if (visible.photo()) {
photo.json.title = (newTitle==="") ? "Untitled" : newTitle;
view.photo.title(oldTitle);
}
album.json.content[photoID].title = newTitle;
view.album.content.title(photoID);
params = "setPhotoTitle&photoID=" + photoID + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
} else if (newTitle.length>0) loadingBar.show("error", "New title to short or too long. Please try another one!");
}],
["Cancel", function() {}]
];
modal.show("Set Title", "Please enter a new title for this photo: <input class='text' type='text' placeholder='Title' value='" + oldTitle + "'>", buttons);
},
setAlbum: function(albumID, photoID) {
var params;
if (albumID>=0) {
// Change reference for the next and previous photo
if (album.json.content[photoID].nextPhoto!==""||album.json.content[photoID].previousPhoto!=="") {
nextPhoto = album.json.content[photoID].nextPhoto;
previousPhoto = album.json.content[photoID].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
if (visible.photo) lychee.goto(album.getID());
album.json.content[photoID] = null;
view.album.content.delete(photoID);
params = "setAlbum&photoID=" + photoID + "&albumID=" + albumID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}
},
setStar: function(photoID) {
var params;
if (visible.photo()) {
photo.json.star = (photo.json.star==0) ? 1 : 0;
view.photo.star();
}
album.json.content[photoID].star = (album.json.content[photoID].star==0) ? 1 : 0;
view.album.content.star(photoID);
params = "setPhotoStar&photoID=" + photoID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setPublic: function(photoID, e) {
var params;
if (photo.json.public==2) {
modal.show("Public Album", "This photo is located in a public album. To make this photo private or public, edit the visibility of the associated album.", [["Show Album", function() { lychee.goto(photo.json.original_album) }], ["Close", function() {}]]);
return false;
}
if (visible.photo()) {
photo.json.public = (photo.json.public==0) ? 1 : 0;
view.photo.public();
if (photo.json.public==1) contextMenu.sharePhoto(photoID, e);
}
album.json.content[photoID].public = (album.json.content[photoID].public==0) ? 1 : 0;
view.album.content.public(photoID);
params = "setPhotoPublic&photoID=" + photoID + "&url=" + photo.getViewLink(photoID);
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setDescription: function(photoID) {
var oldDescription = photo.json.description,
description,
params,
buttons;
buttons = [
["Set Description", function() {
description = $(".message input.text").val();
if (description.length<800) {
if (visible.photo()) {
photo.json.description = description;
view.photo.description();
}
params = "setPhotoDescription&photoID=" + photoID + "&description=" + escape(description);
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
} else loadingBar.show("error", "Description too long. Please try again!");
}],
["Cancel", function() {}]
];
modal.show("Set Description", "Please enter a description for this photo: <input class='text' type='text' placeholder='Description' value='" + oldDescription + "'>", buttons);
},
share: function(photoID, service) {
var link = "",
url = photo.getViewLink(photoID),
filename = "unknown";
switch (service) {
case 0:
link = "https://twitter.com/share?url=" + encodeURI(url);
break;
case 1:
link = "http://www.facebook.com/sharer.php?u=" + encodeURI(url) + "&t=" + encodeURI(photo.json.title);
break;
case 2:
link = "mailto:?subject=" + encodeURI(photo.json.title) + "&body=" + encodeURI(url);
break;
case 3:
lychee.loadDropbox(function() {
filename = photo.json.title + "." + photo.getDirectLink().split('.').pop();
Dropbox.save(photo.getDirectLink(), filename);
});
break;
default:
link = "";
break;
}
if (link.length>5) location.href = link;
},
isSmall: function() {
var size = [
["width", false],
["height", false]
];
if (photo.json.width<$(window).width()-60) size["width"] = true;
if (photo.json.height<$(window).height()-100) size["height"] = true;
if (size["width"]&&size["height"]) return true;
else return false;
},
getArchive: function(photoID) {
var link;
if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", "php/api.php?function=getPhotoArchive&photoID=" + photoID);
else link = location.href.replace(location.hash, "") + "php/api.php?function=getPhotoArchive&photoID=" + photoID;
if (lychee.publicMode) link += "&password=" + password.value;
location.href = link;
},
getDirectLink: function() {
return $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
},
getViewLink: function(photoID) {
if (location.href.indexOf("index.html")>0) return location.href.replace("index.html" + location.hash, "view.php?p=" + photoID);
else return location.href.replace(location.hash, "view.php?p=" + photoID);
}
}

@ -1,468 +0,0 @@
/**
* @name UI View
* @description Responsible to reflect data changes to the UI.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
view = {
header: {
show: function() {
clearTimeout($(window).data("timeout"));
if (visible.photo()) {
lychee.imageview.removeClass("full");
lychee.loadingBar.css("opacity", 1);
lychee.header.removeClass("hidden");
if ($("#imageview #image.small").length>0) {
$("#imageview #image").css({
marginTop: -1*($("#imageview #image").height()/2)+20
});
} else {
$("#imageview #image").css({
top: 60,
right: 30,
bottom: 30,
left: 30
});
}
}
},
hide: function() {
if (visible.photo()&&!visible.infobox()&&!visible.contextMenu()&&!visible.message()) {
clearTimeout($(window).data("timeout"));
$(window).data("timeout", setTimeout(function() {
lychee.imageview.addClass("full");
lychee.loadingBar.css("opacity", 0);
lychee.header.addClass("hidden");
if ($("#imageview #image.small").length>0) {
$("#imageview #image").css({
marginTop: -1*($("#imageview #image").height()/2)
});
} else {
$("#imageview #image").css({
top: 0,
right: 0,
bottom: 0,
left: 0
});
}
}, 500));
}
},
mode: function(mode) {
var albumID = album.getID();
switch (mode) {
case "albums":
lychee.header.removeClass("view");
$("#tools_album, #tools_photo").hide();
$("#tools_albums").show();
break;
case "album":
lychee.header.removeClass("view");
$("#tools_albums, #tools_photo").hide();
$("#tools_album").show();
album.json.content === false ? $("#button_archive").hide() : $("#button_archive").show();
if (albumID==="s"||albumID==="f") {
$("#button_info_album, #button_trash_album, #button_share_album").hide();
} else if (albumID==="0") {
$("#button_info_album, #button_share_album").hide();
$("#button_trash_album").show();
} else {
$("#button_info_album, #button_trash_album, #button_share_album").show();
}
break;
case "photo":
lychee.header.addClass("view");
$("#tools_albums, #tools_album").hide();
$("#tools_photo").show();
break;
}
}
},
infobox: {
show: function() {
if (!visible.infobox()) $("body").append("<div id='infobox_overlay' class='fadeIn'></div>");
lychee.infobox.addClass("active");
},
hide: function() {
lychee.animate("#infobox_overlay", "fadeOut");
setTimeout(function() { $("#infobox_overlay").remove() }, 300);
lychee.infobox.removeClass("active");
}
},
albums: {
init: function() {
view.albums.title();
view.albums.content.init();
},
title: function() {
lychee.setTitle("Albums", false);
},
content: {
init: function() {
var smartData = "",
albumsData = "";
/* Smart Albums */
albums.parse(albums.json.unsortedAlbum);
albums.parse(albums.json.publicAlbum);
albums.parse(albums.json.starredAlbum);
if (!lychee.publicMode) smartData = build.divider("Smart Albums") + build.album(albums.json.unsortedAlbum) + build.album(albums.json.starredAlbum) + build.album(albums.json.publicAlbum);
/* Albums */
if (albums.json.content) {
if (!lychee.publicMode) albumsData = build.divider("Albums");
$.each(albums.json.content, function() {
albums.parse(this);
albumsData += build.album(this);
});
}
if (smartData===""&&albumsData==="") $("body").append(build.no_content("picture"));
else lychee.content.html(smartData + albumsData);
$("img[data-type!='svg']").retina();
},
title: function(albumID) {
var prefix = "",
longTitle = "",
title = albums.json.content[albumID].title;
if (albums.json.content[albumID].password) prefix = "<span class='icon-lock'></span> ";
if (title.length>18) {
longTitle = title;
title = title.substr(0, 18) + "...";
}
$(".album[data-id='" + albumID + "'] .overlay h1")
.html(prefix + title)
.attr("title", longTitle);
},
delete: function(albumID) {
$(".album[data-id='" + albumID + "']").css("opacity", 0).animate({
width: 0,
marginLeft: 0
}, 300, function() {
$(this).remove();
if (albums.json.num<=0) lychee.animate(".divider:last-of-type", "fadeOut");
});
}
}
},
album: {
init: function() {
album.parse();
view.album.infobox();
view.album.title();
view.album.public();
view.album.content.init();
album.json.init = 1;
},
hide: function() {
view.infobox.hide();
},
title: function(oldTitle) {
if ((visible.album()||!album.json.init)&&!visible.photo()) {
switch (album.getID()) {
case "f":
lychee.setTitle("Starred", false);
break;
case "s":
lychee.setTitle("Public", false);
break;
case "0":
lychee.setTitle("Unsorted", false);
break;
default:
if (album.json.init) $("#infobox .attr_name").html(album.json.title + " " + build.editIcon("edit_title_album"));
lychee.setTitle(album.json.title, true);
break;
}
}
},
description: function() {
$("#infobox .attr_description").html(album.json.description + " " + build.editIcon("edit_description_album"));
},
content: {
init: function() {
var photosData = "";
$.each(album.json.content, function() {
album.parse(this);
photosData += build.photo(this);
});
lychee.content.html(photosData);
$("img[data-type!='svg']").retina();
},
title: function(photoID) {
var longTitle = "",
title = album.json.content[photoID].title;
if (title.length>18) {
longTitle = title;
title = title.substr(0, 18) + "...";
}
$(".photo[data-id='" + photoID + "'] .overlay h1")
.html(title)
.attr("title", longTitle);
},
star: function(photoID) {
$(".photo[data-id='" + photoID + "'] .icon-star").remove();
if (album.json.content[photoID].star==1) $(".photo[data-id='" + photoID + "']").append("<a class='badge red icon-star'></a>");
},
public: function(photoID) {
$(".photo[data-id='" + photoID + "'] .icon-share").remove();
if (album.json.content[photoID].public==1) $(".photo[data-id='" + photoID + "']").append("<a class='badge red icon-share'></a>");
},
delete: function(photoID) {
$(".photo[data-id='" + photoID + "']").css("opacity", 0).animate({
width: 0,
marginLeft: 0
}, 300, function() {
$(this).remove();
// Only when search is not active
if (!visible.albums()) {
album.json.num--;
view.album.num();
view.album.title();
}
});
}
},
num: function() {
$("#infobox .attr_images").html(album.json.num);
},
public: function() {
if (album.json.public==1) {
$("#button_share_album a").addClass("active");
$("#button_share_album").attr("title", "Share Album");
$(".photo .icon-share").remove();
if (album.json.init) $("#infobox .attr_visibility").html("Public");
} else {
$("#button_share_album a").removeClass("active");
$("#button_share_album").attr("title", "Make Public");
if (album.json.init) $("#infobox .attr_visibility").html("Private");
}
},
password: function() {
if (album.json.password==1) $("#infobox .attr_password").html("Yes");
else $("#infobox .attr_password").html("No");
},
infobox: function() {
if ((visible.album()||!album.json.init)&&!visible.photo()) lychee.infobox.html(build.infoboxAlbum(album.json)).show();
}
},
photo: {
init: function() {
photo.parse();
view.photo.infobox();
view.photo.title();
view.photo.star();
view.photo.public();
view.photo.photo();
photo.json.init = 1;
},
show: function() {
// Change header
lychee.content.addClass("view");
view.header.mode("photo");
// Make body not scrollable
$("body").css("overflow", "hidden");
// Fullscreen
$(document)
.bind("mouseenter", view.header.show)
.bind("mouseleave", view.header.hide);
lychee.animate(lychee.imageview, "fadeIn");
},
hide: function() {
if (!visible.controls()) view.header.show();
if (visible.infobox) view.infobox.hide();
lychee.content.removeClass("view");
view.header.mode("album");
// Make body scrollable
$("body").css("overflow", "auto");
// Disable Fullscreen
$(document)
.unbind("mouseenter")
.unbind("mouseleave");
// Hide Photo
lychee.animate(lychee.imageview, "fadeOut");
setTimeout(function() {
lychee.imageview.hide();
view.album.infobox();
}, 300);
},
title: function(oldTitle) {
if (photo.json.init) $("#infobox .attr_name").html(photo.json.title + " " + build.editIcon("edit_title"));
lychee.setTitle(photo.json.title, true);
},
description: function() {
if (photo.json.init) $("#infobox .attr_description").html(photo.json.description + " " + build.editIcon("edit_description"));
},
star: function() {
$("#button_star a").removeClass("icon-star-empty icon-star");
if (photo.json.star==1) {
// Starred
$("#button_star a").addClass("icon-star");
$("#button_star").attr("title", "Unstar Photo");
} else {
// Unstarred
$("#button_star a").addClass("icon-star-empty");
$("#button_star").attr("title", "Star Photo");
}
},
public: function() {
if (photo.json.public==1||photo.json.public==2) {
// Photo public
$("#button_share a").addClass("active");
$("#button_share").attr("title", "Share Photo");
if (photo.json.init) $("#infobox .attr_visibility").html("Public");
} else {
// Photo private
$("#button_share a").removeClass("active");
$("#button_share").attr("title", "Make Public");
if (photo.json.init) $("#infobox .attr_visibility").html("Private");
}
},
photo: function() {
lychee.imageview.html(build.imageview(photo.json, photo.isSmall(), visible.controls()));
if ((album.json&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].nextPhoto==="")||lychee.viewMode) $("a#next").hide();
if ((album.json&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].previousPhoto==="")||lychee.viewMode) $("a#previous").hide();
},
infobox: function() {
lychee.infobox.html(build.infoboxPhoto(photo.json)).show();
}
}
}

@ -1,50 +0,0 @@
/**
* @name Visible Module
* @description This module is used to check if elements are visible or not.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
visible = {
albums: function() {
if ($("#tools_albums").css("display")==="block") return true;
else return false;
},
album: function() {
if ($("#tools_album").css("display")==="block") return true;
else return false;
},
photo: function() {
if ($("#imageview.fadeIn").length>0) return true;
else return false;
},
infobox: function() {
if ($("#infobox.active").length>0) return true;
else return false;
},
controls: function() {
if (lychee.loadingBar.css("opacity")<1) return false;
else return true;
},
message: function() {
if ($(".message").length>0) return true;
else return false;
},
signin: function() {
if ($(".message .sign_in").length>0) return true;
else return false;
},
contextMenu: function() {
if ($(".contextmenu").length>0) return true;
else return false;
}
}

@ -0,0 +1,171 @@
/**
* @name Multiselect Module
* @description Select multiple albums or photos.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
multiselect = {
position: {
top: null,
right: null,
bottom: null,
left: null
},
show: function(e) {
if (mobileBrowser()) return false;
if (lychee.publicMode) return false;
if (visible.search()) return false;
if ($('.album:hover, .photo:hover').length!==0) return false;
if (visible.multiselect()) $('#multiselect').remove();
multiselect.position.top = e.pageY;
multiselect.position.right = -1 * (e.pageX - $(document).width());
multiselect.position.bottom = -1 * (multiselect.position.top - $(window).height());
multiselect.position.left = e.pageX;
$('body').append(build.multiselect(multiselect.position.top, multiselect.position.left));
$(document).on('mousemove', multiselect.resize);
},
resize: function(e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
newHeight,
newWidth;
if (multiselect.position.top===null||
multiselect.position.right===null||
multiselect.position.bottom===null||
multiselect.position.left===null) return false;
if (mouse_y>=multiselect.position.top) {
// Do not leave the screen
newHeight = e.pageY - multiselect.position.top;
if ((multiselect.position.top+newHeight)>=$(document).height())
newHeight -= (multiselect.position.top + newHeight) - $(document).height() + 2;
$('#multiselect').css({
top: multiselect.position.top,
bottom: 'inherit',
height: newHeight
});
} else {
$('#multiselect').css({
top: 'inherit',
bottom: multiselect.position.bottom,
height: multiselect.position.top - e.pageY
});
}
if (mouse_x>=multiselect.position.left) {
// Do not leave the screen
newWidth = e.pageX - multiselect.position.left;
if ((multiselect.position.left+newWidth)>=$(document).width())
newWidth -= (multiselect.position.left + newWidth) - $(document).width() + 2;
$('#multiselect').css({
right: 'inherit',
left: multiselect.position.left,
width: newWidth
});
} else {
$('#multiselect').css({
right: multiselect.position.right,
left: 'inherit',
width: multiselect.position.left - e.pageX
});
}
},
stopResize: function() {
$(document).off('mousemove');
},
getSize: function() {
if (!visible.multiselect()) return false;
return {
top: $('#multiselect').offset().top,
left: $('#multiselect').offset().left,
width: parseInt($('#multiselect').css('width').replace('px', '')),
height: parseInt($('#multiselect').css('height').replace('px', ''))
};
},
getSelection: function(e) {
var tolerance = 150,
id,
ids = [],
offset,
size = multiselect.getSize();
if (visible.contextMenu()) return false;
if (!visible.multiselect()) return false;
$('.photo, .album').each(function() {
offset = $(this).offset();
if (offset.top>=(size.top-tolerance)&&
offset.left>=(size.left-tolerance)&&
(offset.top+206)<=(size.top+size.height+tolerance)&&
(offset.left+206)<=(size.left+size.width+tolerance)) {
id = $(this).data('id');
if (id!=='0'&&id!==0&&id!=='f'&&id!=='s'&&id!==null&id!==undefined) {
ids.push(id);
$(this).addClass('active');
}
}
});
if (ids.length!==0&&visible.album()) contextMenu.photoMulti(ids, e);
else if (ids.length!==0&&visible.albums()) contextMenu.albumMulti(ids, e);
else multiselect.close();
},
close: function() {
multiselect.stopResize();
multiselect.position.top = null;
multiselect.position.right = null;
multiselect.position.bottom = null;
multiselect.position.left = null;
lychee.animate('#multiselect', 'fadeOut');
setTimeout(function() {
$('#multiselect').remove();
}, 300);
}
};

@ -0,0 +1,454 @@
/**
* @name Photo Module
* @description Takes care of every action a photo can handle and execute.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
photo = {
json: null,
getID: function() {
var id;
if (photo.json) id = photo.json.id;
else id = $(".photo:hover, .photo.active").attr("data-id");
if (id) return id;
else return false;
},
load: function(photoID, albumID) {
var params,
checkPasswd;
params = "getPhoto&photoID=" + photoID + "&albumID=" + albumID + "&password=" + password.value;
lychee.api(params, function(data) {
if (data==="Warning: Wrong password!") {
checkPasswd = function() {
if (password.value!=="") photo.load(photoID, albumID);
else setTimeout(checkPasswd, 250);
};
checkPasswd();
return false;
}
photo.json = data;
if (!visible.photo()) view.photo.show();
view.photo.init();
lychee.imageview.show();
setTimeout(function() { lychee.content.show() }, 300);
});
},
parse: function() {
if (!photo.json.title) photo.json.title = "Untitled";
photo.json.url = lychee.upload_path_big + photo.json.url;
},
delete: function(photoIDs) {
var params,
buttons,
photoTitle;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
if (photoIDs.length===1) {
// Get title if only one photo is selected
if (visible.photo()) photoTitle = photo.json.title;
else photoTitle = album.json.content[photoIDs].title;
if (photoTitle==="") photoTitle = "Untitled";
}
buttons = [
["", function() {
photoIDs.forEach(function(id, index, array) {
// Change reference for the next and previous photo
if (album.json.content[id].nextPhoto!==""||album.json.content[id].previousPhoto!=="") {
nextPhoto = album.json.content[id].nextPhoto;
previousPhoto = album.json.content[id].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
album.json.content[id] = null;
view.album.content.delete(id);
});
// Only when search is not active
if (!visible.albums()) lychee.goto(album.getID());
params = "deletePhoto&photoIDs=" + photoIDs;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["", function() {}]
];
if (photoIDs.length===1) {
buttons[0][0] = "Delete Photo";
buttons[1][0] = "Keep Photo";
modal.show("Delete Photo", "Are you sure you want to delete the photo '" + photoTitle + "'?<br>This action can't be undone!", buttons);
} else {
buttons[0][0] = "Delete Photos";
buttons[1][0] = "Keep Photos";
modal.show("Delete Photos", "Are you sure you want to delete all " + photoIDs.length + " selected photo?<br>This action can't be undone!", buttons);
}
},
setTitle: function(photoIDs) {
var oldTitle = "",
newTitle,
params,
buttons;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
if (photoIDs.length===1) {
// Get old title if only one photo is selected
if (photo.json) oldTitle = photo.json.title;
else if (album.json) oldTitle = album.json.content[photoIDs].title;
oldTitle = oldTitle.replace("'", "&apos;");
}
buttons = [
["Set Title", function() {
newTitle = $(".message input.text").val();
if (visible.photo()) {
photo.json.title = (newTitle==="") ? "Untitled" : newTitle;
view.photo.title();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].title = newTitle;
view.album.content.title(id);
});
params = "setPhotoTitle&photoIDs=" + photoIDs + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
if (photoIDs.length===1) modal.show("Set Title", "Enter a new title for this photo: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
else modal.show("Set Titles", "Enter a title for all " + photoIDs.length + " selected photos: <input class='text' type='text' maxlength='30' placeholder='Title' value=''>", buttons);
},
setAlbum: function(photoIDs, albumID) {
var params,
nextPhoto,
previousPhoto;
if (!photoIDs) return false;
if (visible.photo) lychee.goto(album.getID());
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
photoIDs.forEach(function(id, index, array) {
// Change reference for the next and previous photo
if (album.json.content[id].nextPhoto!==""||album.json.content[id].previousPhoto!=="") {
nextPhoto = album.json.content[id].nextPhoto;
previousPhoto = album.json.content[id].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
album.json.content[id] = null;
view.album.content.delete(id);
});
params = "setPhotoAlbum&photoIDs=" + photoIDs + "&albumID=" + albumID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setStar: function(photoIDs) {
var params;
if (!photoIDs) return false;
if (visible.photo()) {
photo.json.star = (photo.json.star==0) ? 1 : 0;
view.photo.star();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].star = (album.json.content[id].star==0) ? 1 : 0;
view.album.content.star(id);
});
params = "setPhotoStar&photoIDs=" + photoIDs;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setPublic: function(photoID, e) {
var params;
if (photo.json.public==2) {
modal.show("Public Album", "This photo is located in a public album. To make this photo private or public, edit the visibility of the associated album.", [["Show Album", function() { lychee.goto(photo.json.original_album) }], ["Close", function() {}]]);
return false;
}
if (visible.photo()) {
photo.json.public = (photo.json.public==0) ? 1 : 0;
view.photo.public();
if (photo.json.public==1) contextMenu.sharePhoto(photoID, e);
}
album.json.content[photoID].public = (album.json.content[photoID].public==0) ? 1 : 0;
view.album.content.public(photoID);
params = "setPhotoPublic&photoID=" + photoID + "&url=" + photo.getViewLink(photoID);
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setDescription: function(photoID) {
var oldDescription = photo.json.description.replace("'", "&apos;"),
description,
params,
buttons;
buttons = [
["Set Description", function() {
description = $(".message input.text").val();
if (visible.photo()) {
photo.json.description = description;
view.photo.description();
}
params = "setPhotoDescription&photoID=" + photoID + "&description=" + escape(description);
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("Set Description", "Enter a description for this photo: <input class='text' type='text' maxlength='800' placeholder='Description' value='" + oldDescription + "'>", buttons);
},
editTags: function(photoIDs) {
var oldTags = "",
tags = "";
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
// Get tags
if (visible.photo()) oldTags = photo.json.tags;
if (visible.album()&&photoIDs.length===1) oldTags = album.json.content[photoIDs].tags;
if (visible.album()&&photoIDs.length>1) {
var same = true;
photoIDs.forEach(function(id, index, array) {
if(album.json.content[id].tags===album.json.content[photoIDs[0]].tags&&same===true) same = true;
else same = false;
});
if (same) oldTags = album.json.content[photoIDs[0]].tags;
}
// Improve tags
oldTags = oldTags.replace(/,/g, ', ');
buttons = [
["Set Tags", function() {
tags = $(".message input.text").val();
photo.setTags(photoIDs, tags);
}],
["Cancel", function() {}]
];
if (photoIDs.length===1) modal.show("Set Tags", "Enter your tags for this photo. You can add multiple tags by separating them with a comma: <input class='text' type='text' maxlength='800' placeholder='Tags' value='" + oldTags + "'>", buttons);
else modal.show("Set Tags", "Enter your tags for all " + photoIDs.length + " selected photos. Existing tags will be overwritten. You can add multiple tags by separating them with a comma: <input class='text' type='text' maxlength='800' placeholder='Tags' value='" + oldTags + "'>", buttons);
},
setTags: function(photoIDs, tags) {
var params;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
// Parse tags
tags = tags.replace(/(\ ,\ )|(\ ,)|(,\ )|(,{1,}\ {0,})|(,$|^,)/g, ',');
tags = tags.replace(/,$|^,/g, '');
if (visible.photo()) {
photo.json.tags = tags;
view.photo.tags();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].tags = tags;
});
params = "setPhotoTags&photoIDs=" + photoIDs + "&tags=" + tags;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
deleteTag: function(photoID, index) {
var tags;
// Remove
tags = photo.json.tags.split(',');
tags.splice(index, 1);
// Save
photo.json.tags = tags.toString();
photo.setTags([photoID], photo.json.tags);
},
share: function(photoID, service) {
var link = "",
url = photo.getViewLink(photoID),
filename = "unknown";
switch (service) {
case 0:
link = "https://twitter.com/share?url=" + encodeURI(url);
break;
case 1:
link = "http://www.facebook.com/sharer.php?u=" + encodeURI(url) + "&t=" + encodeURI(photo.json.title);
break;
case 2:
link = "mailto:?subject=" + encodeURI(photo.json.title) + "&body=" + encodeURI(url);
break;
case 3:
lychee.loadDropbox(function() {
filename = photo.json.title + "." + photo.getDirectLink().split('.').pop();
Dropbox.save(photo.getDirectLink(), filename);
});
break;
default:
link = "";
break;
}
if (link.length>5) location.href = link;
},
isSmall: function() {
var size = {
width: false,
height: false
};
if (photo.json.width<$(window).width()-60) size.width = true;
if (photo.json.height<$(window).height()-100) size.height = true;
if (size.width&&size.height) return true;
else return false;
},
getArchive: function(photoID) {
var link;
if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", "php/api.php?function=getPhotoArchive&photoID=" + photoID);
else link = location.href.replace(location.hash, "") + "php/api.php?function=getPhotoArchive&photoID=" + photoID;
if (lychee.publicMode) link += "&password=" + password.value;
location.href = link;
},
getDirectLink: function() {
return $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
},
getViewLink: function(photoID) {
if (location.href.indexOf("index.html")>0) return location.href.replace("index.html" + location.hash, "view.php?p=" + photoID);
else return location.href.replace(location.hash, "view.php?p=" + photoID);
}
};

@ -26,7 +26,7 @@ var settings = {
if (dbHost.length<1) dbHost = "localhost";
if (dbName.length<1) dbName = "lychee";
params = "createConfig&dbName=" + escape(dbName) + "&dbUser=" + escape(dbUser) + "&dbPassword=" + escape(dbPassword) + "&dbHost=" + escape(dbHost);
params = "dbCreateConfig&dbName=" + escape(dbName) + "&dbUser=" + escape(dbUser) + "&dbPassword=" + escape(dbPassword) + "&dbHost=" + escape(dbHost) + "&version=" + escape(lychee.version);
lychee.api(params, function(data) {
if (data!==true) {
@ -53,7 +53,7 @@ var settings = {
["Retry", function() { setTimeout(settings.createConfig, 400) }],
["", function() {}]
];
modal.show("Saving Failed", "Unable to save this configuration. Permission denied in <b>'php/'</b>. Please set the read, write and execute rights for others in <b>'php/'</b> and <b>'uploads/'</b>. Take a look the readme for more information.", buttons, null, false);
modal.show("Saving Failed", "Unable to save this configuration. Permission denied in <b>'data/'</b>. Please set the read, write and execute rights for others in <b>'data/'</b> and <b>'uploads/'</b>. Take a look the readme for more information.", buttons, null, false);
return false;
}
@ -71,7 +71,7 @@ var settings = {
} else {
// Configuration successful
lychee.api("update", function(data) { window.location.reload() });
window.location.reload();
}
@ -80,6 +80,7 @@ var settings = {
}],
["", function() {}]
];
modal.show("Configuration", "Enter your database connection details below: <input id='dbHost' class='text less' type='text' placeholder='Host (optional)' value=''><input id='dbUser' class='text less' type='text' placeholder='Username' value=''><input id='dbPassword' class='text more' type='password' placeholder='Password' value=''><br>Lychee will create its own database. If required, you can enter the name of an existing database instead:<input id='dbName' class='text more' type='text' placeholder='Database (optional)' value=''>", buttons, -215, false);
},
@ -137,6 +138,7 @@ var settings = {
}],
["", function() {}]
];
modal.show("Create Login", "Enter a username and password for your installation: <input id='username' class='text less' type='text' placeholder='New Username' value=''><input id='password' class='text' type='password' placeholder='New Password' value=''>", buttons, -122, false);
},
@ -181,6 +183,7 @@ var settings = {
}],
["Cancel", function() {}]
];
modal.show("Change Login", "Enter your current password: <input id='old_password' class='text more' type='password' placeholder='Current Password' value=''><br>Your username and password will be changed to the following: <input id='username' class='text less' type='text' placeholder='New Username' value=''><input id='password' class='text' type='password' placeholder='New Password' value=''>", buttons, -171);
},
@ -227,12 +230,41 @@ var settings = {
order.\
", buttons);
if (lychee.sorting!="") {
if (lychee.sorting!=="") {
sorting = lychee.sorting.replace("ORDER BY ", "").replace(" ", ";").split(";");
$("select#settings_type").val(sorting[0]);
$("select#settings_order").val(sorting[1]);
}
},
setDropboxKey: function(callback) {
var buttons,
params,
key;
buttons = [
["Set Key", function() {
key = $(".message input.text#key").val();
params = "setDropboxKey&key=" + key;
lychee.api(params, function(data) {
if (data===true) {
lychee.dropboxKey = key;
if (callback) lychee.loadDropbox(callback);
} else lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("Set Dropbox Key", "In order to import photos from your Dropbox, you need a valid drop-ins app key from <a href='https://www.dropbox.com/developers/apps/create'>their website</a>. Generate yourself a personal key and enter it below: <input id='key' class='text' type='text' placeholder='Dropbox API Key' value='" + lychee.dropboxKey + "'>", buttons);
}
}
};

@ -35,20 +35,20 @@ upload = {
$(".upload_message").append("<p>" + text + "</p>");
},
notify: function(title) {
var popup;
if (!window.webkitNotifications) return false;
if (window.webkitNotifications.checkPermission()!=0) window.webkitNotifications.requestPermission();
if (window.webkitNotifications.checkPermission()==0&&title) {
if (window.webkitNotifications.checkPermission()!==0) window.webkitNotifications.requestPermission();
if (window.webkitNotifications.checkPermission()===0&&title) {
popup = window.webkitNotifications.createNotification("", title, "You can now manage your new photo(s).");
popup.show();
}
},
start: {
@ -64,7 +64,7 @@ upload = {
if (files.length<=0) return false;
if (albumID===false) albumID = 0;
formData.append("function", "upload");
formData.append("albumID", albumID);
@ -170,6 +170,7 @@ upload = {
}],
["Cancel", function() {}]
];
modal.show("Import from Link", "Please enter the direct link to a photo to import it: <input class='text' type='text' placeholder='http://' value='http://'>", buttons);
},
@ -194,10 +195,15 @@ upload = {
upload.close();
upload.notify("Import complete");
if (album.getID()===false) lychee.goto("0");
if (data==="Notice: Import only contains albums!") {
if (visible.albums()) lychee.load();
else lychee.goto("");
}
else if (album.getID()===false) lychee.goto("0");
else album.load(albumID);
if (data==="Warning: Folder empty!") lychee.error("Folder empty. No photos imported!", params, data);
if (data==="Notice: Import only contains albums!") return true;
else if (data==="Warning: Folder empty!") lychee.error("Folder empty. No photos imported!", params, data);
else if (data!==true) lychee.error(null, params, data);
});
@ -205,7 +211,8 @@ upload = {
}],
["Cancel", function() {}]
];
modal.show("Import from Server", "This action will import all photos which are located in <b>'uploads/import/'</b> of your Lychee installation.", buttons);
modal.show("Import from Server", "This action will import all photos and albums which are located in <b>'uploads/import/'</b> of your Lychee installation.", buttons);
},
@ -263,4 +270,4 @@ upload = {
}
}
};

@ -1,112 +1,474 @@
/**
* @name View
* @description Used to view single photos with view.php
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
* @name UI View
* @description Responsible to reflect data changes to the UI.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
var header = $("header"),
headerTitle = $("#title"),
imageview = $("#imageview"),
api_path = "php/api.php",
infobox = $("#infobox");
view = {
header: {
show: function() {
clearTimeout($(window).data("timeout"));
if (visible.photo()) {
lychee.imageview.removeClass("full");
lychee.loadingBar.css("opacity", 1);
lychee.header.removeClass("hidden");
if ($("#imageview #image.small").length>0) {
$("#imageview #image").css({
marginTop: -1*($("#imageview #image").height()/2)+20
});
} else {
$("#imageview #image").css({
top: 60,
right: 30,
bottom: 30,
left: 30
});
}
}
$(document).ready(function(){
},
/* Event Name */
if (mobileBrowser()) event_name = "touchend";
else event_name = "click";
hide: function() {
/* Window */
$(window).keydown(key);
if (visible.photo()&&!visible.infobox()&&!visible.contextMenu()&&!visible.message()) {
clearTimeout($(window).data("timeout"));
$(window).data("timeout", setTimeout(function() {
lychee.imageview.addClass("full");
lychee.loadingBar.css("opacity", 0);
lychee.header.addClass("hidden");
if ($("#imageview #image.small").length>0) {
$("#imageview #image").css({
marginTop: -1*($("#imageview #image").height()/2)
});
} else {
$("#imageview #image").css({
top: 0,
right: 0,
bottom: 0,
left: 0
});
}
}, 500));
}
/* Infobox */
$(document).on(event_name, "#infobox .header a", function() { hideInfobox() });
$(document).on(event_name, "#infobox_overlay", function() { hideInfobox() });
$("#button_info").on(event_name, function() { showInfobox() });
},
/* Direct Link */
$("#button_direct").on(event_name, function() {
mode: function(mode) {
link = $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
window.open(link,"_newtab");
var albumID = album.getID();
});
switch (mode) {
case "albums":
lychee.header.removeClass("view");
$("#tools_album, #tools_photo").hide();
$("#tools_albums").show();
break;
case "album":
lychee.header.removeClass("view");
$("#tools_albums, #tools_photo").hide();
$("#tools_album").show();
album.json.content === false ? $("#button_archive").hide() : $("#button_archive").show();
if (albumID==="s"||albumID==="f") {
$("#button_info_album, #button_trash_album, #button_share_album").hide();
} else if (albumID==="0") {
$("#button_info_album, #button_share_album").hide();
$("#button_trash_album").show();
} else {
$("#button_info_album, #button_trash_album, #button_share_album").show();
}
break;
case "photo":
lychee.header.addClass("view");
$("#tools_albums, #tools_album").hide();
$("#tools_photo").show();
break;
loadPhotoInfo(gup("p"));
}
});
}
function key(e) {
},
code = (e.keyCode ? e.keyCode : e.which);
if (code===27&&visibleInfobox()) { hideInfobox(); e.preventDefault(); }
infobox: {
}
show: function() {
function visibleInfobox() {
if (!visible.infobox()) $("body").append("<div id='infobox_overlay' class='fadeIn'></div>");
lychee.infobox.addClass("active");
if (parseInt(infobox.css("right").replace("px", ""))<0) return false;
else return true;
},
}
hide: function() {
function isPhotoSmall(photo) {
lychee.animate("#infobox_overlay", "fadeOut");
setTimeout(function() { $("#infobox_overlay").remove() }, 300);
lychee.infobox.removeClass("active");
size = [
["width", false],
["height", false]
];
}
if (photo.width<$(window).width()-60) size["width"] = true;
if (photo.height<$(window).height()-100) size["height"] = true;
},
if (size["width"]&&size["height"]) return true;
else return false;
albums: {
}
init: function() {
function showInfobox() {
view.albums.title();
view.albums.content.init();
$("body").append("<div id='infobox_overlay' class='fadeIn'></div>");
infobox.addClass("active");
},
}
title: function() {
function hideInfobox() {
lychee.setTitle("Albums", false);
$("#infobox_overlay").removeClass("fadeIn").addClass("fadeOut");
setTimeout(function() { $("#infobox_overlay").remove() }, 300);
infobox.removeClass("active");
},
}
content: {
function loadPhotoInfo(photoID) {
init: function() {
params = "function=getPhoto&photoID=" + photoID + "&albumID=0&password=''";
$.ajax({type: "POST", url: api_path, data: params, dataType: "json", success: function(data) {
var smartData = "",
albumsData = "";
if (!data.title) data.title = "Untitled";
document.title = "Lychee - " + data.title;
headerTitle.html(data.title);
/* Smart Albums */
albums.parse(albums.json.unsortedAlbum);
albums.parse(albums.json.publicAlbum);
albums.parse(albums.json.starredAlbum);
if (!lychee.publicMode) smartData = build.divider("Smart Albums") + build.album(albums.json.unsortedAlbum) + build.album(albums.json.starredAlbum) + build.album(albums.json.publicAlbum);
data.url = "uploads/big/" + data.url;
/* Albums */
if (albums.json.content) {
imageview.attr("data-id", photoID);
if (isPhotoSmall(data)) imageview.html("<div id='image' class='small' style='background-image: url(" + data.url + "); width: " + data.width + "px; height: " + data.height + "px; margin-top: -" + parseInt((data.height/2)-20) + "px; margin-left: -" + data.width/2 + "px;'></div>");
else imageview.html("<div id='image' style='background-image: url(" + data.url + ");'></div>");
imageview.removeClass("fadeOut").addClass("fadeIn").show();
if (!lychee.publicMode) albumsData = build.divider("Albums");
$.each(albums.json.content, function() {
albums.parse(this);
albumsData += build.album(this);
});
infobox.html(build.infoboxPhoto(data, true)).show();
}
}, error: ajaxError });
if (smartData===""&&albumsData==="") $("body").append(build.no_content("picture"));
else lychee.content.html(smartData + albumsData);
}
$("img[data-type!='svg']").retina();
function ajaxError(jqXHR, textStatus, errorThrown) {
},
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
title: function(albumID) {
}
var prefix = "",
longTitle = "",
title = albums.json.content[albumID].title;
if (albums.json.content[albumID].password) prefix = "<span class='icon-lock'></span> ";
if (title.length>18) {
longTitle = title;
title = title.substr(0, 18) + "...";
}
$(".album[data-id='" + albumID + "'] .overlay h1")
.html(prefix + title)
.attr("title", longTitle);
},
delete: function(albumID) {
$(".album[data-id='" + albumID + "']").css("opacity", 0).animate({
width: 0,
marginLeft: 0
}, 300, function() {
$(this).remove();
if (albums.json.num<=0) lychee.animate(".divider:last-of-type", "fadeOut");
});
}
}
},
album: {
init: function() {
album.parse();
view.album.infobox();
view.album.title();
view.album.public();
view.album.content.init();
album.json.init = 1;
},
hide: function() {
view.infobox.hide();
},
title: function() {
if ((visible.album()||!album.json.init)&&!visible.photo()) {
switch (album.getID()) {
case "f":
lychee.setTitle("Starred", false);
break;
case "s":
lychee.setTitle("Public", false);
break;
case "0":
lychee.setTitle("Unsorted", false);
break;
default:
if (album.json.init) $("#infobox .attr_name").html(album.json.title + " " + build.editIcon("edit_title_album"));
lychee.setTitle(album.json.title, true);
break;
}
}
},
description: function() {
$("#infobox .attr_description").html(album.json.description + " " + build.editIcon("edit_description_album"));
},
content: {
init: function() {
var photosData = "";
$.each(album.json.content, function() {
album.parse(this);
photosData += build.photo(this);
});
lychee.content.html(photosData);
$("img[data-type!='svg']").retina();
},
title: function(photoID) {
var longTitle = "",
title = album.json.content[photoID].title;
if (title.length>18) {
longTitle = title;
title = title.substr(0, 18) + "...";
}
$(".photo[data-id='" + photoID + "'] .overlay h1")
.html(title)
.attr("title", longTitle);
},
star: function(photoID) {
$(".photo[data-id='" + photoID + "'] .icon-star").remove();
if (album.json.content[photoID].star==1) $(".photo[data-id='" + photoID + "']").append("<a class='badge red icon-star'></a>");
},
public: function(photoID) {
$(".photo[data-id='" + photoID + "'] .icon-share").remove();
if (album.json.content[photoID].public==1) $(".photo[data-id='" + photoID + "']").append("<a class='badge red icon-share'></a>");
},
delete: function(photoID) {
$(".photo[data-id='" + photoID + "']").css("opacity", 0).animate({
width: 0,
marginLeft: 0
}, 300, function() {
$(this).remove();
// Only when search is not active
if (!visible.albums()) {
album.json.num--;
view.album.num();
view.album.title();
}
});
}
},
num: function() {
$("#infobox .attr_images").html(album.json.num);
},
public: function() {
if (album.json.public==1) {
$("#button_share_album a").addClass("active");
$("#button_share_album").attr("title", "Share Album");
$(".photo .icon-share").remove();
if (album.json.init) $("#infobox .attr_visibility").html("Public");
} else {
$("#button_share_album a").removeClass("active");
$("#button_share_album").attr("title", "Make Public");
if (album.json.init) $("#infobox .attr_visibility").html("Private");
}
},
password: function() {
if (album.json.password==1) $("#infobox .attr_password").html("Yes");
else $("#infobox .attr_password").html("No");
},
infobox: function() {
if ((visible.album()||!album.json.init)&&!visible.photo()) lychee.infobox.html(build.infoboxAlbum(album.json)).show();
}
},
photo: {
init: function() {
photo.parse();
view.photo.infobox();
view.photo.title();
view.photo.star();
view.photo.public();
view.photo.photo();
photo.json.init = 1;
},
show: function() {
// Change header
lychee.content.addClass("view");
view.header.mode("photo");
// Make body not scrollable
$("body").css("overflow", "hidden");
// Fullscreen
$(document)
.bind("mouseenter", view.header.show)
.bind("mouseleave", view.header.hide);
lychee.animate(lychee.imageview, "fadeIn");
},
hide: function() {
if (!visible.controls()) view.header.show();
if (visible.infobox) view.infobox.hide();
lychee.content.removeClass("view");
view.header.mode("album");
// Make body scrollable
$("body").css("overflow", "auto");
// Disable Fullscreen
$(document)
.unbind("mouseenter")
.unbind("mouseleave");
// Hide Photo
lychee.animate(lychee.imageview, "fadeOut");
setTimeout(function() {
lychee.imageview.hide();
view.album.infobox();
}, 300);
},
title: function() {
if (photo.json.init) $("#infobox .attr_name").html(photo.json.title + " " + build.editIcon("edit_title"));
lychee.setTitle(photo.json.title, true);
},
description: function() {
if (photo.json.init) $("#infobox .attr_description").html(photo.json.description + " " + build.editIcon("edit_description"));
},
star: function() {
$("#button_star a").removeClass("icon-star-empty icon-star");
if (photo.json.star==1) {
// Starred
$("#button_star a").addClass("icon-star");
$("#button_star").attr("title", "Unstar Photo");
} else {
// Unstarred
$("#button_star a").addClass("icon-star-empty");
$("#button_star").attr("title", "Star Photo");
}
},
public: function() {
if (photo.json.public==1||photo.json.public==2) {
// Photo public
$("#button_share a").addClass("active");
$("#button_share").attr("title", "Share Photo");
if (photo.json.init) $("#infobox .attr_visibility").html("Public");
} else {
// Photo private
$("#button_share a").removeClass("active");
$("#button_share").attr("title", "Make Public");
if (photo.json.init) $("#infobox .attr_visibility").html("Private");
}
},
tags: function() {
$("#infobox #tags").html(build.tags(photo.json.tags));
},
photo: function() {
lychee.imageview.html(build.imageview(photo.json, photo.isSmall(), visible.controls()));
if ((album.json&&album.json.content&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].nextPhoto==="")||lychee.viewMode) $("a#next").hide();
if ((album.json&&album.json.content&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].previousPhoto==="")||lychee.viewMode) $("a#previous").hide();
},
infobox: function() {
lychee.infobox.html(build.infoboxPhoto(photo.json)).show();
}
}
};

@ -0,0 +1,112 @@
/**
* @name Main
* @description Used to view single photos with view.php
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
var header = $("header"),
headerTitle = $("#title"),
imageview = $("#imageview"),
api_path = "php/api.php",
infobox = $("#infobox");
$(document).ready(function(){
/* Event Name */
if (mobileBrowser()) event_name = "touchend";
else event_name = "click";
/* Window */
$(window).keydown(key);
/* Infobox */
$(document).on(event_name, "#infobox .header a", function() { hideInfobox() });
$(document).on(event_name, "#infobox_overlay", function() { hideInfobox() });
$("#button_info").on(event_name, function() { showInfobox() });
/* Direct Link */
$("#button_direct").on(event_name, function() {
link = $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
window.open(link,"_newtab");
});
loadPhotoInfo(gup("p"));
});
function key(e) {
code = (e.keyCode ? e.keyCode : e.which);
if (code===27&&visibleInfobox()) { hideInfobox(); e.preventDefault(); }
}
function visibleInfobox() {
if (parseInt(infobox.css("right").replace("px", ""))<0) return false;
else return true;
}
function isPhotoSmall(photo) {
size = [
["width", false],
["height", false]
];
if (photo.width<$(window).width()-60) size["width"] = true;
if (photo.height<$(window).height()-100) size["height"] = true;
if (size["width"]&&size["height"]) return true;
else return false;
}
function showInfobox() {
$("body").append("<div id='infobox_overlay' class='fadeIn'></div>");
infobox.addClass("active");
}
function hideInfobox() {
$("#infobox_overlay").removeClass("fadeIn").addClass("fadeOut");
setTimeout(function() { $("#infobox_overlay").remove() }, 300);
infobox.removeClass("active");
}
function loadPhotoInfo(photoID) {
params = "function=getPhoto&photoID=" + photoID + "&albumID=0&password=''";
$.ajax({type: "POST", url: api_path, data: params, dataType: "json", success: function(data) {
if (!data.title) data.title = "Untitled";
document.title = "Lychee - " + data.title;
headerTitle.html(data.title);
data.url = "uploads/big/" + data.url;
imageview.attr("data-id", photoID);
if (isPhotoSmall(data)) imageview.html("<div id='image' class='small' style='background-image: url(" + data.url + "); width: " + data.width + "px; height: " + data.height + "px; margin-top: -" + parseInt((data.height/2)-20) + "px; margin-left: -" + data.width/2 + "px;'></div>");
else imageview.html("<div id='image' style='background-image: url(" + data.url + ");'></div>");
imageview.removeClass("fadeOut").addClass("fadeIn").show();
infobox.html(build.infoboxPhoto(data, true)).show();
}, error: ajaxError });
}
function ajaxError(jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
}

@ -0,0 +1,60 @@
/**
* @name Visible Module
* @description This module is used to check if elements are visible or not.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
visible = {
albums: function() {
if ($('#tools_albums').css('display')==='block') return true;
else return false;
},
album: function() {
if ($('#tools_album').css('display')==='block') return true;
else return false;
},
photo: function() {
if ($('#imageview.fadeIn').length>0) return true;
else return false;
},
search: function() {
if (search.code!==null&&search.code!=='') return true;
else return false;
},
infobox: function() {
if ($('#infobox.active').length>0) return true;
else return false;
},
controls: function() {
if (lychee.loadingBar.css('opacity')<1) return false;
else return true;
},
message: function() {
if ($('.message').length>0) return true;
else return false;
},
signin: function() {
if ($('.message .sign_in').length>0) return true;
else return false;
},
contextMenu: function() {
if ($('.contextmenu').length>0) return true;
else return false;
},
multiselect: function() {
if ($('#multiselect').length>0) return true;
else return false;
}
};

4
data/.gitignore vendored

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

@ -0,0 +1,20 @@
### Dependencies
First you have to install the following dependencies:
- [CSS Optimizer](https://github.com/css/csso) `csso`
- [UglifyJS](https://github.com/mishoo/UglifyJS2) `uglifyjs`
These dependencies can be installed using `npm`:
npm install csso uglify-js -g;
### Build
The Makefile is located in `etc/` and can be easily executed, using the following command. Make sure your run this from the root of Lychee:
make -f etc/Makefile
### Use uncompressed files
While developing, you might want to use the uncompressed files. This is possible by editing the `index.html`. Simply change the linked CSS and JS files. There are already out-commented link-tags for development and production.

@ -1,3 +1,20 @@
## v2.1
Released March 4, 2014
- `New` Multi-select (#32)
- `New` Multi-folder import from server (#47)
- `New` Tagging (#5)
- `New` Import of original image name (#39)
- `New` Makefile
- `Improved` Upload-process
- `Improved` Documentation
- `Improved` Overlay for photos
- `Fixed` Dropbox import (#84)
- `Fixed` Wrong login or password annotation (#71)
- `Fixed` Escaping issue (#89)
- `Moved` Config now located in `data/`
## v2.0.3
Released February 26, 2014

@ -1,5 +1,5 @@
#### Lychee is not working
If Lychee is not working properly, try to open `plugins/check.php`. This script will display all errors it can find. Everything should work if you can see the message "Lychee is ready. Lets rock!".
If Lychee is not working properly, try to open `plugins/check.php`. This script will display all errors it can find.
#### What do I need to run Lychee on my server?
To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database.
@ -18,7 +18,7 @@ If possible, change these settings directly in your `php.ini`. We recommend to i
Lychee supports the latest versions of Google Chrome, Apple Safari, Mozilla Firefox and Opera. Photos you share with others can be viewed from every browser.
#### How can I set thumbnails for my albums?
Thumbnails are chosen automatically by the photos you have starred and in the order you uploaded them. Star a photo inside a album to set it as an thumbnail.
Thumbnails are chosen automatically by the photos you have starred and in the order you uploaded them. Star a photo inside an album to set it as a thumbnail.
#### What is new?
Take a look at the [Changelog](Changelog.md) to see whats new.

@ -1,7 +1,7 @@
### Requirements
### 1. Requirements
Everything you need is a web-server with PHP 5.3 or later and a MySQL-Database.
### PHP configuration `php.ini`
### 2. PHP configuration `php.ini`
The following extensions must be activated:
@ -16,14 +16,22 @@ To use Lychee without restrictions, we recommend to increase the values of the f
upload_max_size = 200M
upload_max_filesize = 20M
max_file_uploads = 100
### 3. Download
### Folder permissions
The easiest way to download Lychee is with `git`:
Change the permissions of `uploads/` and `php/` to 777, including all subfolders:
git clone https://github.com/electerious/Lychee.git
You can also use the [direct download](https://github.com/electerious/Lychee/archive/master.zip).
chmod -R 777 uploads/ php/
### 4. Permissions
### Lychee installation
Change the permissions of `uploads/` and `data/` to 777, including all subfolders:
chmod -R 777 uploads/ data/
### 5. Finish
Open Lychee in your browser and follow the given steps.
If you have trouble, take a look at the [FAQ](FAQ.md).

@ -0,0 +1,47 @@
### Database Details
Your MySQL details are stored in `data/config.php`. This file doesn't exist until you installed Lychee. If you need to change your connection details, you can edit this file manually.
$dbHost = Your MySQL host (in most cases you can use localhost)
$dbUser = Your MySQL username
$dbPassword = Your MySQL password
$dbName = The name of the database you want to use
Fill these properties with your MySQL information. Lychee will create the database and tables for you, if they doesn't exist.
### Settings
All settings are stored in the database. You can change the properties manually, but we recommend to use the menu in Lychee. You can find this menu on the top left corner after you signed in. Some of these settings are only changeable directly in the database.
#### Login
username = Username for Lychee
password = Password for Lychee, saved as an md5 hash
Your photos and albums are protected by an username and password you need to set. If both rows are empty, Lychee will prompt you to set them.
#### Thumb Quality
thumbQuality = [0-100]
Less means an inferiority quality of your thumbs, but faster loading. More means a better quality of your thumbs, but slower loading. The default value is 90. The allowed values are between 0 and 100.
#### Check For Updates
checkForUpdates = [0|1]
If `1`, Lychee will check if you are using the latest version. The notice will be displayed beside the version-number when you sign in.
#### Sorting
sorting = ORDER BY [row] [ASC|DESC]
A typical part of a MySQL statement. This string will be appended to mostly every MySQL query.
#### Dropbox Key
This key is required to use the Dropbox import feature from your server. Lychee will ask you for this key, the first time you try to use the import. You can get your personal drop-ins app key from [their website](https://www.dropbox.com/developers/apps/create).
dropboxKey = Your personal App Key

@ -0,0 +1,11 @@
### Update with `git`
The easiest way to update Lychee is with `git`:
git pull
### Update manually
1. Download the [newest Version](https://github.com/electerious/Lychee/archive/master.zip)
2. Replace all existing files, excluding `uploads/` and `data/`
3. Open Lychee (and enter your database details)

@ -1,32 +0,0 @@
#!/bin/bash
folderCSS="../assets/css"
folderJS="../assets/js"
if [ -e "$folderCSS/modules/" ]
then
echo "Compiling CSS ..."
awk 'FNR==1{print ""}1' $folderCSS/modules/*.css > $folderCSS/min/main.css
csso $folderCSS/min/main.css $folderCSS/min/main.css
echo "CSS compiled!"
else
echo "CSS files not found in $folderCSS"
fi
if [ -e "$folderJS/modules/" ]
then
echo "Compiling JS ..."
awk 'FNR==1{print ""}1' $folderJS/modules/*.js > $folderJS/min/main.js
uglifyjs $folderJS/min/main.js -o $folderJS/min/main.js
echo "JS compiled!"
else
echo "JS files not found in $folderJS"
fi

@ -1,40 +0,0 @@
#!/bin/sh
VERSION='2.0'
echo 'Press ENTER to continue or any other key to abort'
read -s -n 1 key
if [[ "$key" = "" ]]
then
if [ -e Lychee-$VERSION ]
then
echo "The folder 'Lychee-$VERSION' already exists. Please delete it before you try to install Lychee."
exit 1
fi
if [ -e lychee ]
then
echo "The folder 'lychee' already exists. Please delete it before you try to install Lychee."
exit 1
fi
echo 'Downloading and installing Lychee...' && \
curl -sS https://codeload.github.com/electerious/Lychee/zip/v$VERSION > lychee.zip && \
echo 'Downloaded.' && \
echo 'Unzipping...' && \
unzip lychee.zip && \
rm lychee.zip && \
mv Lychee-$VERSION lychee && \
cd lychee && \
echo 'The required directories will be made writable and executable for others. Please enter your password if prompted to do so.' && \
sudo chmod -R 777 uploads php && \
echo 'Installation successful!' && \
exit 0
fi

@ -1,15 +0,0 @@
### Import from server
To import photos from your server (photos you have uploaded via FTP to your server), sign in and click the add-icon on the top right. Then choose 'Import from Server'.
### Upload and share single photos [Depreciated]
Important: This feature is depreciated and will be removed with the next major version. Do not use it anymore! It will be replaced by a plugin.
You can upload photos directly with every FTP client into Lychee. This feature helps you to share single images quickly with others.
1. Upload an image to `uploads/import/`
2. Navigate your browser to the place where Lychee is located (e.g. `http://example.com/view.php?p=filename.png`). `filename.png` must be replaced with the filename of your uploaded file.
3. Share the link.
Lychee will import the file as an public image, delete the original (unused) file and display it in the browser. [Sample FTP configuration](http://l.electerious.com/view.php?p=13657692738813).

@ -1,41 +0,0 @@
### Database Details
Your MySQL details are stored in `php/config.php`. This file doesn't exist until you installed Lychee. If you need to change your connection details, you can edit this file manually.
$dbHost = Your MySQL host (in most cases you can use localhost)
$dbUser = Your MySQL username
$dbPassword = Your MySQL password
$dbName = The name of the database you want to use
Fill these properties with your MySQL information. Lychee will create the database and tables for you, if they doesn't exist.
### Settings
All settings are stored in the database. You can change the properties manually, but we recommend to use the menu in Lychee. You can find this menu on the top left corner after you signed in.
#### Login
username = Username for Lychee
password = Password for Lychee, saved as an md5 hash
Your photos and albums are protected by a username and password you need to set. If both rows are empty, Lychee will prompt you to set them.
#### Thumb Quality
thumbQuality = [0-100]
Less means a inferiority quality of your thumbs, but faster loading. More means a better quality of your thumbs, but slower loading. The default value is 90. The allowed values are between 0 and 100.
#### Check For Updates
checkForUpdates = [0|1]
If `1`, Lychee will check if you are using the latest version. The notice will be displayed beside the version-number when you sign in.
#### Sorting
sorting = ORDER BY [row] [ASC|DESC]
A typical part of an MySQL statement. This string will be appended to mostly every MySQL query.

@ -0,0 +1,35 @@
NO_COLOR=\x1b[0m
OK_COLOR=\x1b[32;01m
ERROR_COLOR=\x1b[31;01m
WARN_COLOR=\x1b[33;01m
OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR)
ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR)
RUN_STRING=$(WARN_COLOR)[RUN]$(NO_COLOR)
ROOT = .
CSS = '$(ROOT)/assets/css'
JS = '$(ROOT)/assets/js'
BUILD = '$(ROOT)/assets/build'
all: clean create css js
clean:
rm -f -R $(BUILD)
@echo "$(OK_STRING) Clean build"
create: clean
mkdir $(BUILD)
@echo "$(OK_STRING) Create build"
css: create
@echo "$(RUN_STRING) Compiling CSS"
awk 'FNR==1{print ""}1' $(CSS)/*.css > $(BUILD)/main.css
csso $(BUILD)/main.css $(BUILD)/main.css
@echo "$(OK_STRING) CSS compiled"
js: create
@echo "$(RUN_STRING) Compiling JS"
awk 'FNR==1{print ""}1' $(JS)/*.js > $(BUILD)/main.js
uglifyjs $(BUILD)/main.js -o $(BUILD)/main.js
@echo "$(OK_STRING) JS compiled"

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

@ -9,28 +9,27 @@
<meta name="keywords" content="">
<meta name="description" content="">
<!-- CSS -->
<link type="text/css" rel="stylesheet" href="assets/css/min/reset.css">
<!-- Development
<link type="text/css" rel="stylesheet" href="assets/css/modules/upload.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/tooltip.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/misc.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/message.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/mediaquery.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/loading.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/infobox.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/imageview.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/header.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/font.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/contextmenu.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/content.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/animations.css"> -->
<!-- Production -->
<link type="text/css" rel="stylesheet" href="assets/css/min/main.css">
<link rel="shortcut icon" href="assets/img/favicon.ico">
<!-- Development -->
<link type="text/css" rel="stylesheet" href="assets/css/_reset.css">
<link type="text/css" rel="stylesheet" href="assets/css/upload.css">
<link type="text/css" rel="stylesheet" href="assets/css/tooltip.css">
<link type="text/css" rel="stylesheet" href="assets/css/misc.css">
<link type="text/css" rel="stylesheet" href="assets/css/message.css">
<link type="text/css" rel="stylesheet" href="assets/css/mediaquery.css">
<link type="text/css" rel="stylesheet" href="assets/css/loading.css">
<link type="text/css" rel="stylesheet" href="assets/css/infobox.css">
<link type="text/css" rel="stylesheet" href="assets/css/imageview.css">
<link type="text/css" rel="stylesheet" href="assets/css/header.css">
<link type="text/css" rel="stylesheet" href="assets/css/font.css">
<link type="text/css" rel="stylesheet" href="assets/css/contextmenu.css">
<link type="text/css" rel="stylesheet" href="assets/css/content.css">
<link type="text/css" rel="stylesheet" href="assets/css/animations.css">
<link type="text/css" rel="stylesheet" href="assets/css/multiselect.css">
<!-- Production
<link type="text/css" rel="stylesheet" href="assets/build/main.css"> -->
<link rel="shortcut icon" href="favicon.ico">
<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-iphone.png" sizes="120x120">
<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-ipad.png" sizes="152x152">
@ -96,28 +95,27 @@
<input id="upload_files" type="file" name="fileElem[]" multiple accept="image/*">
</div>
<!-- JS -->
<script defer type="text/javascript" src="assets/js/min/frameworks.js"></script>
<!-- Development
<script defer type="text/javascript" src="assets/js/modules/init.js"></script>
<script defer type="text/javascript" src="assets/js/modules/lychee.js"></script>
<script defer type="text/javascript" src="assets/js/modules/build.js"></script>
<script defer type="text/javascript" src="assets/js/modules/settings.js"></script>
<script defer type="text/javascript" src="assets/js/modules/upload.js"></script>
<script defer type="text/javascript" src="assets/js/modules/view.js"></script>
<script defer type="text/javascript" src="assets/js/modules/password.js"></script>
<script defer type="text/javascript" src="assets/js/modules/modal.js"></script>
<script defer type="text/javascript" src="assets/js/modules/album.js"></script>
<script defer type="text/javascript" src="assets/js/modules/albums.js"></script>
<script defer type="text/javascript" src="assets/js/modules/photo.js"></script>
<script defer type="text/javascript" src="assets/js/modules/visible.js"></script>
<script defer type="text/javascript" src="assets/js/modules/loadingBar.js"></script>
<script defer type="text/javascript" src="assets/js/modules/contextMenu.js"></script>
<script defer type="text/javascript" src="assets/js/modules/search.js"></script> -->
<!-- Production -->
<script defer type="text/javascript" src="assets/js/min/main.js"></script>
<!-- Development -->
<script defer type="text/javascript" src="assets/js/_frameworks.js"></script>
<script defer type="text/javascript" src="assets/js/init.js"></script>
<script defer type="text/javascript" src="assets/js/lychee.js"></script>
<script defer type="text/javascript" src="assets/js/build.js"></script>
<script defer type="text/javascript" src="assets/js/settings.js"></script>
<script defer type="text/javascript" src="assets/js/upload.js"></script>
<script defer type="text/javascript" src="assets/js/view.js"></script>
<script defer type="text/javascript" src="assets/js/password.js"></script>
<script defer type="text/javascript" src="assets/js/modal.js"></script>
<script defer type="text/javascript" src="assets/js/album.js"></script>
<script defer type="text/javascript" src="assets/js/albums.js"></script>
<script defer type="text/javascript" src="assets/js/photo.js"></script>
<script defer type="text/javascript" src="assets/js/visible.js"></script>
<script defer type="text/javascript" src="assets/js/loadingBar.js"></script>
<script defer type="text/javascript" src="assets/js/contextMenu.js"></script>
<script defer type="text/javascript" src="assets/js/search.js"></script>
<script defer type="text/javascript" src="assets/js/multiselect.js"></script>
<!-- Production
<script defer type="text/javascript" src="assets/build/main.js"></script> -->
</body>
</html>

@ -0,0 +1,157 @@
<?php
/**
* @name Admin Access
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
if (!defined('LYCHEE_ACCESS_ADMIN')) exit('Error: You are not allowed to access this area!');
switch ($_POST['function']) {
// Album Functions
case 'getAlbums': echo json_encode(getAlbums(false));
break;
case 'getAlbum': if (isset($_POST['albumID']))
echo json_encode(getAlbum($_POST['albumID']));
break;
case 'addAlbum': if (isset($_POST['title']))
echo addAlbum($_POST['title']);
break;
case 'setAlbumTitle': if (isset($_POST['albumIDs'])&&isset($_POST['title']))
echo setAlbumTitle($_POST['albumIDs'], $_POST['title']);
break;
case 'setAlbumDescription': if (isset($_POST['albumID'])&&isset($_POST['description']))
echo setAlbumDescription($_POST['albumID'], $_POST['description']);
break;
case 'setAlbumPublic': if (isset($_POST['albumID']))
if (!isset($_POST['password'])) $_POST['password'] = '';
echo setAlbumPublic($_POST['albumID'], $_POST['password']);
break;
case 'setAlbumPassword': if (isset($_POST['albumID'])&&isset($_POST['password']))
echo setAlbumPassword($_POST['albumID'], $_POST['password']);
break;
case 'deleteAlbum': if (isset($_POST['albumIDs']))
echo deleteAlbum($_POST['albumIDs']);
break;
// Photo Functions
case 'getPhoto': if (isset($_POST['photoID'])&&isset($_POST['albumID']))
echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
break;
case 'deletePhoto': if (isset($_POST['photoIDs']))
echo deletePhoto($_POST['photoIDs']);
break;
case 'setPhotoAlbum': if (isset($_POST['photoIDs'])&&isset($_POST['albumID']))
echo setPhotoAlbum($_POST['photoIDs'], $_POST['albumID']);
break;
case 'setPhotoTitle': if (isset($_POST['photoIDs'])&&isset($_POST['title']))
echo setPhotoTitle($_POST['photoIDs'], $_POST['title']);
break;
case 'setPhotoStar': if (isset($_POST['photoIDs']))
echo setPhotoStar($_POST['photoIDs']);
break;
case 'setPhotoPublic': if (isset($_POST['photoID'])&&isset($_POST['url']))
echo setPhotoPublic($_POST['photoID'], $_POST['url']);
break;
case 'setPhotoDescription': if (isset($_POST['photoID'])&&isset($_POST['description']))
echo setPhotoDescription($_POST['photoID'], $_POST['description']);
break;
case 'setPhotoTags': if (isset($_POST['photoIDs'])&&isset($_POST['tags']))
echo setPhotoTags($_POST['photoIDs'], $_POST['tags']);
break;
// Add Functions
case 'upload': if (isset($_FILES)&&isset($_POST['albumID']))
echo upload($_FILES, $_POST['albumID']);
break;
case 'importUrl': if (isset($_POST['url'])&&isset($_POST['albumID']))
echo importUrl($_POST['url'], $_POST['albumID']);
break;
case 'importServer': if (isset($_POST['albumID']))
echo importServer($_POST['albumID']);
break;
// Search Function
case 'search': if (isset($_POST['term']))
echo json_encode(search($_POST['term']));
break;
// Session Function
case 'init': echo json_encode(init('admin', $_POST['version']));
break;
case 'login': if (isset($_POST['user'])&&isset($_POST['password']))
echo login($_POST['user'], $_POST['password']);
break;
case 'logout': logout();
break;
// Settings
case 'setLogin': if (isset($_POST['username'])&&isset($_POST['password']))
if (!isset($_POST['oldPassword'])) $_POST['oldPassword'] = '';
echo setLogin($_POST['oldPassword'], $_POST['username'], $_POST['password']);
break;
case 'setSorting': if (isset($_POST['type'])&&isset($_POST['order']))
echo setSorting($_POST['type'], $_POST['order']);
break;
case 'setDropboxKey': if (isset($_POST['key']))
echo setDropboxKey($_POST['key']);
break;
// Miscellaneous
default: switch ($_GET['function']) {
case 'getFeed': if (isset($_GET['albumID']))
echo getFeed($_GET['albumID']);
break;
case 'getAlbumArchive': if (isset($_GET['albumID']))
getAlbumArchive($_GET['albumID']);
break;
case 'getPhotoArchive': if (isset($_GET['photoID']))
getPhotoArchive($_GET['photoID']);
break;
case 'update': echo update();
break;
default: exit('Error: Function not found! Please check the spelling of the called function.');
break;
}
break;
}
?>

@ -0,0 +1,126 @@
<?php
/**
* @name Guest Access (Public Mode)
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
if (!defined('LYCHEE_ACCESS_GUEST')) exit('Error: You are not allowed to access this area!');
switch ($_POST['function']) {
// Album Functions
case 'getAlbums': echo json_encode(getAlbums(true));
break;
case 'getAlbum': if (isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isAlbumPublic($_POST['albumID'])) {
// Album Public
if (checkAlbumPassword($_POST['albumID'], $_POST['password']))
echo json_encode(getAlbum($_POST['albumID']));
else
echo 'Warning: Wrong password!';
} else {
// Album Private
echo 'Warning: Album private!';
}
}
break;
case 'checkAlbumAccess':if (isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isAlbumPublic($_POST['albumID'])) {
// Album Public
if (checkAlbumPassword($_POST['albumID'], $_POST['password']))
echo true;
else
echo false;
} else {
// Album Private
echo false;
}
}
break;
// Photo Functions
case 'getPhoto': if (isset($_POST['photoID'])&&isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isPhotoPublic($_POST['photoID'], $_POST['password']))
echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
else
echo 'Warning: Wrong password!';
}
break;
// Session Functions
case 'init': echo json_encode(init('public', $_POST['version']));
break;
case 'login': if (isset($_POST['user'])&&isset($_POST['password']))
echo login($_POST['user'], $_POST['password']);
break;
// Miscellaneous
default: switch ($_GET['function']) {
case 'getFeed': if (isset($_GET['albumID'])&&isset($_GET['password'])) {
// Album Feed
if (isAlbumPublic($_GET['albumID'])) {
// Album Public
if (checkAlbumPassword($_GET['albumID'], $_GET['password']))
echo getFeed($_GET['albumID']);
else
exit('Warning: Wrong password!');
} else {
// Album Private
exit('Warning: Album private!');
}
}
break;
case 'getAlbumArchive': if (isset($_GET['albumID'])&&isset($_GET['password'])) {
// Album Download
if (isAlbumPublic($_GET['albumID'])) {
// Album Public
if (checkAlbumPassword($_GET['albumID'], $_GET['password']))
getAlbumArchive($_GET['albumID']);
else
exit('Warning: Wrong password!');
} else {
// Album Private
exit('Warning: Album private or not downloadable!');
}
}
break;
case 'getPhotoArchive': if (isset($_GET['photoID'])&&isset($_GET['password'])) {
// Photo Download
if (isPhotoPublic($_GET['photoID'], $_GET['password']))
// Photo Public
getPhotoArchive($_GET['photoID']);
else
// Photo Private
exit('Warning: Photo private or not downloadable!');
}
break;
default: exit('Error: Function not found! Please check the spelling of the called function.');
break;
}
break;
}
?>

@ -0,0 +1,23 @@
<?php
/**
* @name Installation Access
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
if (!defined('LYCHEE_ACCESS_INSTALLATION')) exit('Error: You are not allowed to access this area!');
switch ($_POST['function']) {
case 'dbCreateConfig': if (isset($_POST['dbHost'])&&isset($_POST['dbUser'])&&isset($_POST['dbPassword'])&&isset($_POST['dbName'])&&isset($_POST['version']))
echo dbCreateConfig($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['version']);
break;
default: echo 'Warning: No configuration!';
break;
}
?>

@ -1,10 +1,9 @@
<?php
/**
* @name API
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @name API
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
@ini_set('max_execution_time', '200');
@ -17,290 +16,68 @@ if (!empty($_POST['function'])||!empty($_GET['function'])) {
session_start();
define('LYCHEE', true);
date_default_timezone_set('UTC');
// Load modules
require('modules/album.php');
require('modules/db.php');
require('modules/misc.php');
require('modules/photo.php');
require('modules/session.php');
require('modules/settings.php');
require('modules/upload.php');
require('modules/album.php');
require('modules/photo.php');
require('modules/misc.php');
if (file_exists('config.php')) require('config.php');
if (file_exists('../data/config.php')) require('../data/config.php');
else {
/**
* Installation Mode
* Installation Access
* Limited access to configure Lychee. Only available when the config.php file is missing.
*/
switch ($_POST['function']) {
case 'createConfig': if (isset($_POST['dbHost'])&&isset($_POST['dbUser'])&&isset($_POST['dbPassword'])&&isset($_POST['dbName']))
echo createConfig($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName']);
break;
default: echo 'Warning: No configuration!';
break;
}
define('LYCHEE_ACCESS_INSTALLATION', true);
require('access/installation.php');
exit();
}
// Connect to DB
// Connect and get settings
$database = dbConnect();
// Get Settings
$settings = getSettings();
// Security
if (isset($_POST['albumID'])&&($_POST['albumID']==''||$_POST['albumID']<0||$_POST['albumID']>10000)) exit('Error: Wrong parameter type for albumID!');
if (isset($_POST['photoID'])&&$_POST['photoID']=='') exit('Error: Wrong parameter type for photoID!');
foreach(array_keys($_POST) as $key) $_POST[$key] = mysqli_real_escape_string($database, urldecode($_POST[$key]));
foreach(array_keys($_GET) as $key) $_GET[$key] = mysqli_real_escape_string($database, urldecode($_GET[$key]));
// Escape
foreach(array_keys($_POST) as $key) $_POST[$key] = mysqli_real_escape_string($database, urldecode($_POST[$key]));
foreach(array_keys($_GET) as $key) $_GET[$key] = mysqli_real_escape_string($database, urldecode($_GET[$key]));
// Validate parameters
if (isset($_POST['albumIDs'])&&preg_match('/^[0-9\,]{1,}$/', $_POST['albumIDs'])!==1) exit('Error: Wrong parameter type for albumIDs!');
if (isset($_POST['photoIDs'])&&preg_match('/^[0-9\,]{1,}$/', $_POST['photoIDs'])!==1) exit('Error: Wrong parameter type for photoIDs!');
if (isset($_POST['albumID'])&&preg_match('/^[0-9sf]{1,}$/', $_POST['albumID'])!==1) exit('Error: Wrong parameter type for albumID!');
if (isset($_POST['photoID'])&&preg_match('/^[0-9]{14}$/', $_POST['photoID'])!==1) exit('Error: Wrong parameter type for photoID!');
// Fallback for switch statement
if (!isset($_POST['function'])) $_POST['function'] = '';
if (!isset($_GET['function'])) $_GET['function'] = '';
if (isset($_SESSION['login'])&&$_SESSION['login']==true) {
/**
* Admin Mode
* Admin Access
* Full access to Lychee. Only with correct password/session.
*/
switch ($_POST['function']) {
// Album Functions
case 'getAlbums': echo json_encode(getAlbums(false));
break;
case 'getAlbum': if (isset($_POST['albumID']))
echo json_encode(getAlbum($_POST['albumID']));
break;
case 'addAlbum': if (isset($_POST['title']))
echo addAlbum($_POST['title']);
break;
case 'setAlbumTitle': if (isset($_POST['albumID'])&&isset($_POST['title']))
echo setAlbumTitle($_POST['albumID'], $_POST['title']);
break;
case 'setAlbumDescription': if (isset($_POST['albumID'])&&isset($_POST['description']))
echo setAlbumDescription($_POST['albumID'], $_POST['description']);
break;
case 'setAlbumPublic': if (isset($_POST['albumID']))
if (!isset($_POST['password'])) $_POST['password'] = '';
echo setAlbumPublic($_POST['albumID'], $_POST['password']);
break;
case 'setAlbumPassword':if (isset($_POST['albumID'])&&isset($_POST['password']))
echo setAlbumPassword($_POST['albumID'], $_POST['password']);
break;
case 'deleteAlbum': if (isset($_POST['albumID']))
echo deleteAlbum($_POST['albumID']);
break;
// Photo Functions
case 'getPhoto': if (isset($_POST['photoID'])&&isset($_POST['albumID']))
echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
break;
case 'deletePhoto': if (isset($_POST['photoID']))
echo deletePhoto($_POST['photoID']);
break;
case 'setAlbum': if (isset($_POST['photoID'])&&isset($_POST['albumID']))
echo setAlbum($_POST['photoID'], $_POST['albumID']);
break;
case 'setPhotoTitle': if (isset($_POST['photoID'])&&isset($_POST['title']))
echo setPhotoTitle($_POST['photoID'], $_POST['title']);
break;
case 'setPhotoStar': if (isset($_POST['photoID']))
echo setPhotoStar($_POST['photoID']);
break;
case 'setPhotoPublic': if (isset($_POST['photoID'])&&isset($_POST['url']))
echo setPhotoPublic($_POST['photoID'], $_POST['url']);
break;
case 'setPhotoDescription': if (isset($_POST['photoID'])&&isset($_POST['description']))
echo setPhotoDescription($_POST['photoID'], $_POST['description']);
break;
// Add Functions
case 'upload': if (isset($_FILES)&&isset($_POST['albumID']))
echo upload($_FILES, $_POST['albumID']);
break;
case 'importUrl': if (isset($_POST['url'])&&isset($_POST['albumID']))
echo importUrl($_POST['url'], $_POST['albumID']);
break;
case 'importServer': if (isset($_POST['albumID']))
echo importServer($_POST['albumID']);
break;
// Search Function
case 'search': if (isset($_POST['term']))
echo json_encode(search($_POST['term']));
break;
// Session Function
case 'init': echo json_encode(init('admin'));
break;
case 'login': if (isset($_POST['user'])&&isset($_POST['password']))
echo login($_POST['user'], $_POST['password']);
break;
case 'logout': logout();
break;
// Settings
case 'setLogin': if (isset($_POST['username'])&&isset($_POST['password']))
if (!isset($_POST['oldPassword'])) $_POST['oldPassword'] = '';
echo setLogin($_POST['oldPassword'], $_POST['username'], $_POST['password']);
break;
case 'setSorting': if (isset($_POST['type'])&&isset($_POST['order']))
echo setSorting($_POST['type'], $_POST['order']);
break;
// Miscellaneous
case 'update': echo update();
default: if (isset($_GET['function'])&&$_GET['function']=='getAlbumArchive'&&isset($_GET['albumID']))
// Album Download
getAlbumArchive($_GET['albumID']);
else if (isset($_GET['function'])&&$_GET['function']=='getPhotoArchive'&&isset($_GET['photoID']))
// Photo Download
getPhotoArchive($_GET['photoID']);
else if (isset($_GET['function'])&&$_GET['function']=='update')
// Update Lychee
echo update();
else
// Function unknown
exit('Error: Function not found! Please check the spelling of the called function.');
break;
}
define('LYCHEE_ACCESS_ADMIN', true);
require('access/admin.php');
} else {
/**
* Public Mode
* Guest Access
* Access to view all public folders and photos in Lychee.
*/
switch ($_POST['function']) {
// Album Functions
case 'getAlbums': echo json_encode(getAlbums(true));
break;
case 'getAlbum': if (isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isAlbumPublic($_POST['albumID'])) {
// Album Public
if (checkAlbumPassword($_POST['albumID'], $_POST['password']))
echo json_encode(getAlbum($_POST['albumID']));
else
echo 'Warning: Wrong password!';
} else {
// Album Private
echo 'Warning: Album private!';
}
}
break;
case 'checkAlbumAccess':if (isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isAlbumPublic($_POST['albumID'])) {
// Album Public
if (checkAlbumPassword($_POST['albumID'], $_POST['password']))
echo true;
else
echo false;
} else {
// Album Private
echo false;
}
}
break;
// Photo Functions
case 'getPhoto': if (isset($_POST['photoID'])&&isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isPhotoPublic($_POST['photoID'], $_POST['password']))
echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
else
echo 'Warning: Wrong password!';
}
break;
// Session Functions
case 'init': echo json_encode(init('public'));
break;
case 'login': if (isset($_POST['user'])&&isset($_POST['password']))
echo login($_POST['user'], $_POST['password']);
break;
// Miscellaneous
default: if (isset($_GET['function'])&&$_GET['function']=='getAlbumArchive'&&isset($_GET['albumID'])&&isset($_GET['password'])) {
// Album Download
if (isAlbumPublic($_GET['albumID'])) {
// Album Public
if (checkAlbumPassword($_GET['albumID'], $_GET['password']))
getAlbumArchive($_GET['albumID']);
else
exit('Warning: Wrong password!');
} else {
// Album Private
exit('Warning: Album private or not downloadable!');
}
} else if (isset($_GET['function'])&&$_GET['function']=='getPhotoArchive'&&isset($_GET['photoID'])&&isset($_GET['password'])) {
// Photo Download
if (isPhotoPublic($_GET['photoID'], $_GET['password']))
// Photo Public
getPhotoArchive($_GET['photoID']);
else
// Photo Private
exit('Warning: Photo private or not downloadable!');
} else {
// Function unknown
exit('Error: Function not found! Please check the spelling of the called function.');
}
break;
}
define('LYCHEE_ACCESS_GUEST', true);
require('access/guest.php');
}

@ -1,10 +1,10 @@
<?php
/**
* @name Album Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @name Album Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
@ -13,12 +13,13 @@ function addAlbum($title) {
global $database;
if (strlen($title)<1||strlen($title)>30) return false;
$sysdate = date("d.m.Y");
$result = $database->query("INSERT INTO lychee_albums (title, sysdate) VALUES ('$title', '$sysdate');");
if (!$result) return false;
if (strlen($title)<1||strlen($title)>50) return false;
return $database->insert_id;
$sysdate = date("d.m.Y");
$result = $database->query("INSERT INTO lychee_albums (title, sysdate) VALUES ('$title', '$sysdate');");
if (!$result) return false;
return $database->insert_id;
}
@ -26,49 +27,52 @@ function getAlbums($public) {
global $database, $settings;
// Smart Albums
if (!$public) $return = getSmartInfo();
// Albums
if ($public) $query = "SELECT * FROM lychee_albums WHERE public = 1";
else $query = "SELECT * FROM lychee_albums";
$result = $database->query($query) OR exit("Error: $result <br>".$database->error);
$i = 0;
while($row = $result->fetch_object()) {
// Info
$return["content"][$row->id]['id'] = $row->id;
$return["content"][$row->id]['title'] = $row->title;
$return["content"][$row->id]['public'] = $row->public;
$return["content"][$row->id]['sysdate'] = date('F Y', strtotime($row->sysdate));
if ($row->password=="") $return["content"][$row->id]['password'] = false;
else $return["content"][$row->id]['password'] = true;
// Thumbs
if (($public&&$row->password=="")||(!$public)) {
$albumID = $row->id;
$result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = '$albumID' ORDER BY star DESC, " . substr($settings['sorting'], 9) . " LIMIT 0, 3");
$k = 0;
while($row2 = $result2->fetch_object()){
$return["content"][$row->id]["thumb$k"] = $row2->thumbUrl;
$k++;
}
if (!isset($return["content"][$row->id]["thumb0"])) $return["content"][$row->id]["thumb0"] = "";
if (!isset($return["content"][$row->id]["thumb1"])) $return["content"][$row->id]["thumb1"] = "";
if (!isset($return["content"][$row->id]["thumb2"])) $return["content"][$row->id]["thumb2"] = "";
}
// Album count
$i++;
}
$return["num"] = $i;
if ($i==0) $return["albums"] = false;
else $return["albums"] = true;
return $return;
// Smart Albums
if (!$public) $return = getSmartInfo();
// Albums
if ($public) $query = "SELECT id, title, public, sysdate, password FROM lychee_albums WHERE public = 1";
else $query = "SELECT id, title, public, sysdate, password FROM lychee_albums";
$result = $database->query($query) OR exit("Error: $result <br>".$database->error);
$i = 0;
while($row = $result->fetch_object()) {
// Info
$return["content"][$row->id]['id'] = $row->id;
$return["content"][$row->id]['title'] = $row->title;
$return["content"][$row->id]['public'] = $row->public;
$return["content"][$row->id]['sysdate'] = date('F Y', strtotime($row->sysdate));
// Password
if ($row->password=="") $return["content"][$row->id]['password'] = false;
else $return["content"][$row->id]['password'] = true;
// Thumbs
if (($public&&$row->password=="")||(!$public)) {
$albumID = $row->id;
$result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = '$albumID' ORDER BY star DESC, " . substr($settings['sorting'], 9) . " LIMIT 0, 3");
$k = 0;
while($row2 = $result2->fetch_object()){
$return["content"][$row->id]["thumb$k"] = $row2->thumbUrl;
$k++;
}
if (!isset($return["content"][$row->id]["thumb0"])) $return["content"][$row->id]["thumb0"] = "";
if (!isset($return["content"][$row->id]["thumb1"])) $return["content"][$row->id]["thumb1"] = "";
if (!isset($return["content"][$row->id]["thumb2"])) $return["content"][$row->id]["thumb2"] = "";
}
// Album count
$i++;
}
$return["num"] = $i;
return $return;
}
@ -77,33 +81,33 @@ function getSmartInfo() {
global $database, $settings;
// Unsorted
$result = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = 0 " . $settings['sorting']);
$i = 0;
while($row = $result->fetch_object()) {
if ($i<3) $return["unsortedThumb$i"] = $row->thumbUrl;
$i++;
}
$return['unsortedNum'] = $i;
$result = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = 0 " . $settings['sorting']);
$i = 0;
while($row = $result->fetch_object()) {
if ($i<3) $return["unsortedThumb$i"] = $row->thumbUrl;
$i++;
}
$return['unsortedNum'] = $i;
// Public
$result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE public = 1 " . $settings['sorting']);
$i = 0;
while($row2 = $result2->fetch_object()) {
if ($i<3) $return["publicThumb$i"] = $row2->thumbUrl;
$i++;
}
$return['publicNum'] = $i;
$result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE public = 1 " . $settings['sorting']);
$i = 0;
while($row2 = $result2->fetch_object()) {
if ($i<3) $return["publicThumb$i"] = $row2->thumbUrl;
$i++;
}
$return['publicNum'] = $i;
// Starred
$result3 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE star = 1 " . $settings['sorting']);
$i = 0;
while($row3 = $result3->fetch_object()) {
if ($i<3) $return["starredThumb$i"] = $row3->thumbUrl;
$i++;
}
$return['starredNum'] = $i;
$result3 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE star = 1 " . $settings['sorting']);
$i = 0;
while($row3 = $result3->fetch_object()) {
if ($i<3) $return["starredThumb$i"] = $row3->thumbUrl;
$i++;
}
$return['starredNum'] = $i;
return $return;
return $return;
}
@ -114,51 +118,51 @@ function getAlbum($albumID) {
// Get album information
switch($albumID) {
case "f": $return['public'] = false;
$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE star = 1 " . $settings['sorting'];
break;
case "f": $return['public'] = false;
$query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE star = 1 " . $settings['sorting'];
break;
case "s": $return['public'] = false;
$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE public = 1 " . $settings['sorting'];
break;
case "s": $return['public'] = false;
$query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE public = 1 " . $settings['sorting'];
break;
case "0": $return['public'] = false;
$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = 0 " . $settings['sorting'];
case "0": $return['public'] = false;
$query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = 0 " . $settings['sorting'];
break;
default: $result = $database->query("SELECT * FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
$return['title'] = $row->title;
$return['description'] = $row->description;
$return['sysdate'] = date('d M. Y', strtotime($row->sysdate));
$return['public'] = $row->public;
if ($row->password=="") $return['password'] = false;
else $return['password'] = true;
$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = '$albumID' " . $settings['sorting'];
break;
default: $result = $database->query("SELECT * FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
$return['title'] = $row->title;
$return['description'] = $row->description;
$return['sysdate'] = date('d M. Y', strtotime($row->sysdate));
$return['public'] = $row->public;
$return['password'] = ($row->password=="" ? false : true);
$query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = '$albumID' " . $settings['sorting'];
break;
}
// Get photos
$result = $database->query($query);
$previousPhotoID = "";
$i = 0;
$result = $database->query($query);
$previousPhotoID = "";
$i = 0;
while($row = $result->fetch_array()) {
$return['content'][$row['id']]['id'] = $row['id'];
$return['content'][$row['id']]['title'] = $row['title'];
$return['content'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate']));
$return['content'][$row['id']]['public'] = $row['public'];
$return['content'][$row['id']]['star'] = $row['star'];
$return['content'][$row['id']]['album'] = $row['album'];
$return['content'][$row['id']]['thumbUrl'] = $row['thumbUrl'];
$return['content'][$row['id']]['id'] = $row['id'];
$return['content'][$row['id']]['title'] = $row['title'];
$return['content'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate']));
$return['content'][$row['id']]['public'] = $row['public'];
$return['content'][$row['id']]['star'] = $row['star'];
$return['content'][$row['id']]['tags'] = $row['tags'];
$return['content'][$row['id']]['album'] = $row['album'];
$return['content'][$row['id']]['thumbUrl'] = $row['thumbUrl'];
$return['content'][$row['id']]['previousPhoto'] = $previousPhotoID;
$return['content'][$row['id']]['nextPhoto'] = "";
if ($previousPhotoID!="") $return['content'][$previousPhotoID]['nextPhoto'] = $row['id'];
$return['content'][$row['id']]['previousPhoto'] = $previousPhotoID;
$return['content'][$row['id']]['nextPhoto'] = "";
if ($previousPhotoID!="") $return['content'][$previousPhotoID]['nextPhoto'] = $row['id'];
$previousPhotoID = $row['id'];
$i++;
$previousPhotoID = $row['id'];
$i++;
}
@ -170,34 +174,34 @@ function getAlbum($albumID) {
} else {
// Enable next and previous for the first and last photo
$lastElement = end($return['content']);
$lastElementId = $lastElement['id'];
$firstElement = reset($return['content']);
$firstElementId = $firstElement['id'];
$lastElement = end($return['content']);
$lastElementId = $lastElement['id'];
$firstElement = reset($return['content']);
$firstElementId = $firstElement['id'];
if ($lastElementId!==$firstElementId) {
$return['content'][$lastElementId]['nextPhoto'] = $firstElementId;
$return['content'][$firstElementId]['previousPhoto'] = $lastElementId;
$return['content'][$lastElementId]['nextPhoto'] = $firstElementId;
$return['content'][$firstElementId]['previousPhoto'] = $lastElementId;
}
}
$return['id'] = $albumID;
$return['num'] = $i;
$return['id'] = $albumID;
$return['num'] = $i;
return $return;
}
function setAlbumTitle($albumID, $title) {
function setAlbumTitle($albumIDs, $title) {
global $database;
if (strlen($title)<1||strlen($title)>30) return false;
$result = $database->query("UPDATE lychee_albums SET title = '$title' WHERE id = '$albumID';");
if (!$result) return false;
if (strlen($title)<1||strlen($title)>50) return false;
$result = $database->query("UPDATE lychee_albums SET title = '$title' WHERE id IN ($albumIDs);");
return true;
if (!$result) return false;
return true;
}
@ -206,32 +210,30 @@ function setAlbumDescription($albumID, $description) {
global $database;
$description = htmlentities($description);
if (strlen($description)>800) return false;
$result = $database->query("UPDATE lychee_albums SET description = '$description' WHERE id = '$albumID';");
if (strlen($description)>1000) return false;
$result = $database->query("UPDATE lychee_albums SET description = '$description' WHERE id = '$albumID';");
if (!$result) return false;
return true;
if (!$result) return false;
return true;
}
function deleteAlbum($albumID) {
function deleteAlbum($albumIDs) {
global $database;
$error = false;
$error = false;
$result = $database->query("SELECT id FROM lychee_photos WHERE album IN ($albumIDs);");
$result = $database->query("SELECT id FROM lychee_photos WHERE album = '$albumID';");
while($row = $result->fetch_object()) {
if (!deletePhoto($row->id)) $error = true;
}
// Delete photos
while ($row = $result->fetch_object())
if (!deletePhoto($row->id)) $error = true;
if ($albumID!=0) {
$result = $database->query("DELETE FROM lychee_albums WHERE id = '$albumID';");
if (!$result) return false;
}
// Delete album
$result = $database->query("DELETE FROM lychee_albums WHERE id IN ($albumIDs);");
if ($error) return false;
return true;
if ($error||!$result) return false;
return true;
}
@ -239,53 +241,54 @@ function getAlbumArchive($albumID) {
global $database;
switch($albumID) {
case 's':
$query = "SELECT * FROM lychee_photos WHERE public = '1';";
$zipTitle = "Public";
break;
case 'f':
$query = "SELECT * FROM lychee_photos WHERE star = '1';";
$zipTitle = "Starred";
break;
default:
$query = "SELECT * FROM lychee_photos WHERE album = '$albumID';";
$zipTitle = "Unsorted";
}
$result = $database->query($query);
$files = array();
$i=0;
while($row = $result->fetch_object()) {
$files[$i] = "../uploads/big/".$row->url;
$i++;
}
$result = $database->query("SELECT * FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
if ($albumID!=0&&is_numeric($albumID))$zipTitle = $row->title;
$filename = "../uploads/".$zipTitle.".zip";
$zip = new ZipArchive();
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
return false;
}
foreach($files AS $zipFile) {
$newFile = explode("/",$zipFile);
$newFile = array_reverse($newFile);
$zip->addFile($zipFile, $zipTitle."/".$newFile[0]);
}
$zip->close();
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=\"$zipTitle.zip\"");
header("Content-Length: ".filesize($filename));
readfile($filename);
unlink($filename);
return true;
switch($albumID) {
case 's':
$query = "SELECT url FROM lychee_photos WHERE public = '1';";
$zipTitle = "Public";
break;
case 'f':
$query = "SELECT url FROM lychee_photos WHERE star = '1';";
$zipTitle = "Starred";
break;
default:
$query = "SELECT url FROM lychee_photos WHERE album = '$albumID';";
$zipTitle = "Unsorted";
}
$zip = new ZipArchive();
$result = $database->query($query);
$files = array();
$i = 0;
while($row = $result->fetch_object()) {
$files[$i] = "../uploads/big/".$row->url;
$i++;
}
$result = $database->query("SELECT title FROM lychee_albums WHERE id = '$albumID' LIMIT 1;");
$row = $result->fetch_object();
if ($albumID!=0&&is_numeric($albumID)) $zipTitle = $row->title;
$filename = "../data/$zipTitle.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
return false;
}
foreach($files AS $zipFile) {
$newFile = explode("/",$zipFile);
$newFile = array_reverse($newFile);
$zip->addFile($zipFile, $zipTitle."/".$newFile[0]);
}
$zip->close();
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=\"$zipTitle.zip\"");
header("Content-Length: ".filesize($filename));
readfile($filename);
unlink($filename);
return true;
}
@ -293,22 +296,20 @@ function setAlbumPublic($albumID, $password) {
global $database;
$result = $database->query("SELECT public FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
if ($row->public == 0){
$public = 1;
} else {
$public = 0;
}
$result = $database->query("SELECT public FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
$public = ($row->public=='0' ? 1 : 0);
$result = $database->query("UPDATE lychee_albums SET public = '$public', password = NULL WHERE id = '$albumID';");
if (!$result) return false;
if ($public==1) {
$result = $database->query("UPDATE lychee_photos SET public = 0 WHERE album = '$albumID';");
if (!$result) return false;
}
if (strlen($password)>0) return setAlbumPassword($albumID, $password);
else return true;
return true;
}
@ -327,12 +328,12 @@ function checkAlbumPassword($albumID, $password) {
global $database;
$result = $database->query("SELECT password FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
if ($row->password=="") return true;
$result = $database->query("SELECT password FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
if ($row->password=="") return true;
else if ($row->password==$password) return true;
else return false;
return false;
}
@ -340,11 +341,12 @@ function isAlbumPublic($albumID) {
global $database;
$result = $database->query("SELECT public FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
$result = $database->query("SELECT public FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object();
if ($albumID==='0'||$albumID==='s'||$albumID==='f') return false;
if ($row->public==1) return true;
else return false;
return false;
}

@ -1,66 +1,56 @@
<?php
/**
* @name DB Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @name DB Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
function dbConnect() {
global $dbUser, $dbPassword, $dbHost, $dbName;
global $dbUser, $dbPassword, $dbHost, $dbName;
$database = new mysqli($dbHost, $dbUser, $dbPassword);
if (mysqli_connect_errno()) {
echo mysqli_connect_errno().': '.mysqli_connect_error();
return false;
}
$database = new mysqli($dbHost, $dbUser, $dbPassword);
if (!$database->select_db($dbName))
if (!createDatabase($dbName, $database)) exit('Error: Could not create database!');
if (!$database->query("SELECT * FROM lychee_photos, lychee_albums, lychee_settings LIMIT 1;"))
if (!createTables($database)) exit('Error: Could not create tables!');
if ($database->connect_errno) exit('Error: ' . $database->connect_error);
// Avoid sql injection on older MySQL versions
// Avoid sql injection on older MySQL versions
if ($database->server_version<50500) $database->set_charset('GBK');
return $database;
}
function dbClose() {
global $database;
if (!$database->select_db($dbName))
if (!dbCreate($dbName, $database)) exit('Error: Could not create database!');
if (!$database->close()) exit("Error: Closing the connection failed!");
if (!$database->query('SELECT * FROM lychee_photos, lychee_albums, lychee_settings LIMIT 0;'))
if (!dbCreateTables($database)) exit('Error: Could not create tables!');
return true;
return $database;
}
function createConfig($dbHost = 'localhost', $dbUser, $dbPassword, $dbName = 'lychee') {
function dbCreateConfig($dbHost = 'localhost', $dbUser, $dbPassword, $dbName = 'lychee', $version) {
$dbPassword = urldecode($dbPassword);
$database = new mysqli($dbHost, $dbUser, $dbPassword);
$dbPassword = urldecode($dbPassword);
$database = new mysqli($dbHost, $dbUser, $dbPassword);
if (mysqli_connect_errno()||$dbUser=="") return "Warning: Connection failed!";
if ($database->connect_errno) return 'Warning: Connection failed!';
else {
$config = "<?php
/**
* @name Config
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @name Config
* @author Tobias Reich
* @copyright 2014 Tobias Reich
*/
if(!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
// Config version
\$configVersion = '';
// Database configurations
\$dbHost = '$dbHost'; //Host of the Database
\$dbUser = '$dbUser'; //Username of the database
@ -69,19 +59,16 @@ if(!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
?>";
if (file_put_contents("config.php", $config)===false) return "Warning: Could not create file!";
else {
$_SESSION['login'] = true;
return true;
if (file_put_contents('../data/config.php', $config)===false) return 'Warning: Could not create file!';
}
$_SESSION['login'] = true;
return true;
}
}
function createDatabase($dbName, $database) {
function dbCreate($dbName, $database) {
$result = $database->query("CREATE DATABASE IF NOT EXISTS $dbName;");
$database->select_db($dbName);
@ -91,9 +78,9 @@ function createDatabase($dbName, $database) {
}
function createTables($database) {
function dbCreateTables($database) {
if (!$database->query("SELECT * FROM lychee_settings;")) {
if (!$database->query('SELECT * FROM lychee_settings LIMIT 0;')) {
$query = "
@ -114,7 +101,8 @@ function createTables($database) {
('password',''),
('thumbQuality','90'),
('checkForUpdates','1'),
('sorting','ORDER BY id DESC');
('sorting','ORDER BY id DESC'),
('dropboxKey','');
";
@ -122,7 +110,7 @@ function createTables($database) {
}
if (!$database->query("SELECT * FROM lychee_albums;")) {
if (!$database->query('SELECT * FROM lychee_albums LIMIT 0;')) {
$query = "
@ -138,11 +126,11 @@ function createTables($database) {
";
if (!$database->query($query)) return false;
if (!$database->query($query)) return false;
}
}
if (!$database->query("SELECT * FROM lychee_photos;")) {
if (!$database->query('SELECT * FROM lychee_photos LIMIT 0;')) {
$query = "
@ -151,6 +139,7 @@ function createTables($database) {
`title` varchar(50) NOT NULL,
`description` varchar(1000) NOT NULL DEFAULT '',
`url` varchar(100) NOT NULL,
`tags` varchar(1000) NOT NULL DEFAULT '',
`public` tinyint(1) NOT NULL,
`type` varchar(10) NOT NULL,
`width` int(11) NOT NULL,
@ -175,11 +164,21 @@ function createTables($database) {
";
if (!$database->query($query)) return false;
if (!$database->query($query)) return false;
}
return true;
}
}
function dbClose() {
return true;
global $database;
if (!$database->close()) exit('Error: Closing the connection failed!');
return true;
}

@ -1,10 +1,10 @@
<?php
/**
* @name Misc Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @name Misc Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
@ -14,18 +14,17 @@ function openGraphHeader($photoID) {
global $database;
$photoID = mysqli_real_escape_string($database, $photoID);
if (!is_numeric($photoID)) return false;
$result = $database->query("SELECT * FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object();
$result = $database->query("SELECT title, description, url FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object();
$parseUrl = parse_url("http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
$picture = $parseUrl['scheme']."://".$parseUrl['host'].$parseUrl['path']."/../uploads/big/".$row->url;
$parseUrl = parse_url("http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
$picture = $parseUrl['scheme']."://".$parseUrl['host'].$parseUrl['path']."/../uploads/big/".$row->url;
$return = '<!-- General Meta Data -->';
$return = '<!-- General Meta Data -->';
$return .= '<meta name="title" content="'.$row->title.'" />';
$return .= '<meta name="description" content="'.$row->description.' - via Lychee" />';
$return .= '<link rel="image_src" type="image/jpeg" href="'.$picture.'" />';
$return .= '<link rel="image_src" type="image/jpeg" href="'.$picture.'" />';
$return .= '<!-- Twitter Meta Data -->';
$return .= '<meta name="twitter:card" content="photo">';
@ -36,7 +35,7 @@ function openGraphHeader($photoID) {
$return .= '<meta property="og:title" content="'.$row->title.'">';
$return .= '<meta property="og:image" content="'.$picture.'">';
return $return;
return $return;
}
@ -44,52 +43,69 @@ function search($term) {
global $database, $settings;
$return["albums"] = "";
$return['albums'] = '';
$result = $database->query("SELECT * FROM lychee_photos WHERE title like '%$term%' OR description like '%$term%';");
while($row = $result->fetch_array()) {
$return['photos'][$row['id']] = $row;
$return['photos'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate']));
}
// Photos
$result = $database->query("SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE title like '%$term%' OR description like '%$term%' OR tags like '%$term%';");
while($row = $result->fetch_array()) {
$return['photos'][$row['id']] = $row;
$return['photos'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate']));
}
$result = $database->query("SELECT * FROM lychee_albums WHERE title like '%$term%';");
$i=0;
while($row = $result->fetch_object()) {
// Albums
$result = $database->query("SELECT id, title, public, sysdate, password FROM lychee_albums WHERE title like '%$term%' OR description like '%$term%';");
$i = 0;
while($row = $result->fetch_object()) {
$return["albums"][$row->id]['id'] = $row->id;
$return["albums"][$row->id]['title'] = $row->title;
$return["albums"][$row->id]['public'] = $row->public;
$return["albums"][$row->id]['sysdate'] = date('F Y', strtotime($row->sysdate));
if ($row->password=="") $return["albums"][$row->id]['password'] = false;
else $return["albums"][$row->id]['password'] = true;
// Info
$return['albums'][$row->id]['id'] = $row->id;
$return['albums'][$row->id]['title'] = $row->title;
$return['albums'][$row->id]['public'] = $row->public;
$return['albums'][$row->id]['sysdate'] = date('F Y', strtotime($row->sysdate));
$return['albums'][$row->id]['password'] = ($row->password=='' ? false : true);
$result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = '" . $row->id . "' " . $settings['sorting'] . " LIMIT 0, 3;");
$k = 0;
while($row2 = $result2->fetch_object()){
$return['albums'][$row->id]["thumb$k"] = $row2->thumbUrl;
$k++;
}
$i++;
// Thumbs
$result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = '" . $row->id . "' " . $settings['sorting'] . " LIMIT 0, 3;");
$k = 0;
while($row2 = $result2->fetch_object()){
$return['albums'][$row->id]["thumb$k"] = $row2->thumbUrl;
$k++;
}
}
$i++;
return $return;
}
return $return;
}
function update() {
function update($version = '') {
global $database;
global $database, $configVersion;
if(!$database->query("SELECT `public` FROM `lychee_albums`;")) $database->query("ALTER TABLE `lychee_albums` ADD `public` TINYINT( 1 ) NOT NULL DEFAULT '0'");
if(!$database->query("SELECT `password` FROM `lychee_albums`;")) $database->query("ALTER TABLE `lychee_albums` ADD `password` VARCHAR( 100 ) NULL DEFAULT ''");
if(!$database->query("SELECT `description` FROM `lychee_albums`;")) $database->query("ALTER TABLE `lychee_albums` ADD `description` VARCHAR( 1000 ) NULL DEFAULT ''");
if($database->query("SELECT `password` FROM `lychee_albums`;")) $database->query("ALTER TABLE `lychee_albums` CHANGE `password` `password` VARCHAR( 100 ) NULL DEFAULT ''");
// Albums
if(!$database->query("SELECT `public` FROM `lychee_albums` LIMIT 1;")) $database->query("ALTER TABLE `lychee_albums` ADD `public` TINYINT( 1 ) NOT NULL DEFAULT '0'");
if(!$database->query("SELECT `password` FROM `lychee_albums` LIMIT 1;")) $database->query("ALTER TABLE `lychee_albums` ADD `password` VARCHAR( 100 ) NULL DEFAULT ''");
if(!$database->query("SELECT `description` FROM `lychee_albums` LIMIT 1;")) $database->query("ALTER TABLE `lychee_albums` ADD `description` VARCHAR( 1000 ) NULL DEFAULT ''");
if($database->query("SELECT `password` FROM `lychee_albums` LIMIT 1;")) $database->query("ALTER TABLE `lychee_albums` CHANGE `password` `password` VARCHAR( 100 ) NULL DEFAULT ''");
if($database->query("SELECT `description` FROM `lychee_photos`;")) $database->query("ALTER TABLE `lychee_photos` CHANGE `description` `description` VARCHAR( 1000 ) NULL DEFAULT ''");
if($database->query("SELECT `shortlink` FROM `lychee_photos`;")) $database->query("ALTER TABLE `lychee_photos` DROP `shortlink`");
// Photos
if($database->query("SELECT `description` FROM `lychee_photos` LIMIT 1;")) $database->query("ALTER TABLE `lychee_photos` CHANGE `description` `description` VARCHAR( 1000 ) NULL DEFAULT ''");
if(!$database->query("SELECT `tags` FROM `lychee_photos` LIMIT 1;")) $database->query("ALTER TABLE `lychee_photos` ADD `tags` VARCHAR( 1000 ) NULL DEFAULT ''");
$database->query("UPDATE `lychee_photos` SET url = replace(url, 'uploads/big/', ''), thumbUrl = replace(thumbUrl, 'uploads/thumb/', '')");
// Settings
$result = $database->query("SELECT `key` FROM `lychee_settings` WHERE `key` = 'dropboxKey' LIMIT 1;");
if ($result->num_rows===0) $database->query("INSERT INTO `lychee_settings` (`key`, `value`) VALUES ('dropboxKey', '')");
// Config
if ($version!==''&&$configVersion!==$version) {
$data = file_get_contents('../data/config.php');
$data = preg_replace('/\$configVersion = \'[\w. ]*\';/', "\$configVersion = '$version';", $data);
if (file_put_contents('../data/config.php', $data)===false) return 'Error: Could not save updated config!';
}
return true;
}

@ -1,10 +1,10 @@
<?php
/**
* @name Photo Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @name Photo Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
@ -13,43 +13,30 @@ function getPhoto($photoID, $albumID) {
global $database;
if (!is_numeric($photoID)) {
$result = $database->query("SELECT COUNT(*) AS quantity FROM lychee_photos WHERE import_name = '../uploads/import/$photoID';");
$row = $result->fetch_object();
if ($row->quantity == 0) {
importPhoto($photoID, 's');
}
if (is_file("../uploads/import/$photoID")) {
importPhoto($photoID, 's');
}
$query = "SELECT * FROM lychee_photos WHERE import_name = '../uploads/import/$photoID' ORDER BY ID DESC;";
} else {
$query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
}
$query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
$result = $database->query($query);
$return = $result->fetch_array();
$result = $database->query($query);
$return = $result->fetch_array();
if ($albumID!='false') {
if ($albumID!='false') {
if ($return['album']!=0) {
if ($return['album']!=0) {
$result = $database->query("SELECT public FROM lychee_albums WHERE id = '" . $return['album'] . "';");
$return_album = $result->fetch_array();
if ($return_album['public']=="1") $return['public'] = "2";
$result = $database->query("SELECT public FROM lychee_albums WHERE id = '" . $return['album'] . "';");
$return_album = $result->fetch_array();
if ($return_album['public']=="1") $return['public'] = "2";
}
}
$return['original_album'] = $return['album'];
$return['album'] = $albumID;
$return['sysdate'] = date('d M. Y', strtotime($return['sysdate']));
if (strlen($return['takedate'])>0) $return['takedate'] = date('d M. Y', strtotime($return['takedate']));
$return['original_album'] = $return['album'];
$return['album'] = $albumID;
$return['sysdate'] = date('d M. Y', strtotime($return['sysdate']));
if (strlen($return['takedate'])>0) $return['takedate'] = date('d M. Y', strtotime($return['takedate']));
}
unset($return['album_public']);
return $return;
return $return;
}
@ -57,56 +44,56 @@ function setPhotoPublic($photoID, $url) {
global $database;
$result = $database->query("SELECT public FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object();
if ($row->public == 0){
$public = 1;
} else {
$public = 0;
}
$result = $database->query("UPDATE lychee_photos SET public = '$public' WHERE id = '$photoID';");
$result = $database->query("SELECT public FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object();
$public = ($row->public==0 ? 1 : 0);
$result = $database->query("UPDATE lychee_photos SET public = '$public' WHERE id = '$photoID';");
if (!$result) return false;
return true;
if (!$result) return false;
return true;
}
function setPhotoStar($photoID) {
function setPhotoStar($photoIDs) {
global $database;
$result = $database->query("SELECT star FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object();
if ($row->star == 0) {
$star = 1;
} else {
$star = 0;
}
$result = $database->query("UPDATE lychee_photos SET star = '$star' WHERE id = '$photoID';");
return true;
$error = false;
$result = $database->query("SELECT id, star FROM lychee_photos WHERE id IN ($photoIDs);");
while ($row = $result->fetch_object()) {
$star = ($row->star==0 ? 1 : 0);
$star = $database->query("UPDATE lychee_photos SET star = '$star' WHERE id = '$row->id';");
if (!$star) $error = true;
}
if ($error) return false;
return true;
}
function setAlbum($photoID, $newAlbum) {
function setPhotoAlbum($photoIDs, $albumID) {
global $database;
$result = $database->query("UPDATE lychee_photos SET album = '$newAlbum' WHERE id = '$photoID';");
$result = $database->query("UPDATE lychee_photos SET album = '$albumID' WHERE id IN ($photoIDs);");
if (!$result) return false;
else return true;
if (!$result) return false;
return true;
}
function setPhotoTitle($photoID, $title) {
function setPhotoTitle($photoIDs, $title) {
global $database;
if (strlen($title)>30) return false;
$result = $database->query("UPDATE lychee_photos SET title = '$title' WHERE id = '$photoID';");
if (strlen($title)>50) return false;
$result = $database->query("UPDATE lychee_photos SET title = '$title' WHERE id IN ($photoIDs);");
if (!$result) return false;
else return true;
if (!$result) return false;
return true;
}
@ -114,31 +101,58 @@ function setPhotoDescription($photoID, $description) {
global $database;
$description = htmlentities($description);
if (strlen($description)>800) return false;
$result = $database->query("UPDATE lychee_photos SET description = '$description' WHERE id = '$photoID';");
$description = htmlentities($description);
if (strlen($description)>1000) return false;
if (!$result) return false;
return true;
$result = $database->query("UPDATE lychee_photos SET description = '$description' WHERE id = '$photoID';");
if (!$result) return false;
return true;
}
function deletePhoto($photoID) {
function setPhotoTags($photoIDs, $tags) {
global $database;
$result = $database->query("SELECT * FROM lychee_photos WHERE id = '$photoID';");
if (!$result) return false;
$row = $result->fetch_object();
$retinaUrl = explode(".", $row->thumbUrl);
$unlink1 = unlink("../uploads/big/".$row->url);
$unlink2 = unlink("../uploads/thumb/".$row->thumbUrl);
$unlink3 = unlink("../uploads/thumb/".$retinaUrl[0].'@2x.'.$retinaUrl[1]);
$result = $database->query("DELETE FROM lychee_photos WHERE id = '$photoID';");
if (!$unlink1 || !$unlink2 || !$unlink3) return false;
if (!$result) return false;
// Parse tags
$tags = preg_replace('/(\ ,\ )|(\ ,)|(,\ )|(,{1,}\ {0,})|(,$|^,)/', ',', $tags);
$tags = preg_replace('/,$|^,/', ',', $tags);
return true;
if (strlen($tags)>1000) return false;
$result = $database->query("UPDATE lychee_photos SET tags = '$tags' WHERE id IN ($photoIDs);");
if (!$result) return false;
return true;
}
function deletePhoto($photoIDs) {
global $database;
$result = $database->query("SELECT id, url, thumbUrl FROM lychee_photos WHERE id IN ($photoIDs);");
while ($row = $result->fetch_object()) {
// Get retina thumb url
$thumbUrl2x = explode(".", $row->thumbUrl);
$thumbUrl2x = $thumbUrl2x[0] . '@2x.' . $thumbUrl2x[1];
// Delete files
if (!unlink('../uploads/big/' . $row->url)) return false;
if (!unlink('../uploads/thumb/' . $row->thumbUrl)) return false;
if (!unlink('../uploads/thumb/' . $thumbUrl2x)) return false;
// Delete db entry
$delete = $database->query("DELETE FROM lychee_photos WHERE id = $row->id;");
if (!$delete) return false;
}
if (!$result) return false;
return true;
}
@ -146,21 +160,18 @@ function isPhotoPublic($photoID, $password) {
global $database;
if (is_numeric($photoID)) {
$query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
} else {
$query = "SELECT * FROM lychee_photos WHERE import_name = '../uploads/import/$photoID';";
$query = "SELECT public, album FROM lychee_photos WHERE id = '$photoID';";
$result = $database->query($query);
$row = $result->fetch_object();
if ($row->public==1) return true;
else {
$cAP = checkAlbumPassword($row->album, $password);
$iAP = isAlbumPublic($row->album);
if ($iAP&&$cAP) return true;
return false;
}
$result = $database->query($query);
$row = $result->fetch_object();
if (!is_numeric($photoID)&&!$row) return true;
if ($row->public==1) return true;
else {
$cAP = checkAlbumPassword($row->album, $password);
$iAP = isAlbumPublic($row->album);
if ($iAP&&$cAP) return true;
else return false;
}
}
@ -168,8 +179,8 @@ function getPhotoArchive($photoID) {
global $database;
$result = $database->query("SELECT * FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object();
$result = $database->query("SELECT title, url FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object();
$extension = array_reverse(explode('.', $row->url));

@ -1,17 +1,21 @@
<?php
/**
* @name Session Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @name Session Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
function init($mode) {
function init($mode, $version) {
global $settings;
global $settings, $configVersion;
// Update
if ($configVersion!==$version)
if (!update($version)) exit('Error: Updating the database failed!');
$return['config'] = $settings;
unset($return['config']['password']);
@ -26,6 +30,7 @@ function init($mode) {
unset($return['config']['username']);
unset($return['config']['thumbQuality']);
unset($return['config']['sorting']);
unset($return['config']['dropboxKey']);
unset($return['config']['login']);
$return['loggedIn'] = false;
}
@ -39,16 +44,16 @@ function login($username, $password) {
global $database, $settings;
// Check login
if ($username===$settings['username']&&$password===$settings['password']) {
$_SESSION['login'] = true;
return true;
}
if ($username===$settings['username']&&$password===$settings['password']) {
$_SESSION['login'] = true;
return true;
}
// No login
if ($settings['username']===''&&$settings['password']==='') {
$_SESSION['login'] = true;
return true;
}
// No login
if ($settings['username']===''&&$settings['password']==='') {
$_SESSION['login'] = true;
return true;
}
return false;
@ -56,8 +61,8 @@ function login($username, $password) {
function logout() {
session_destroy();
return true;
session_destroy();
return true;
}

@ -1,9 +1,9 @@
<?php
/**
* @name Settings Module
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
* @name Settings Module
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
@ -15,7 +15,7 @@ function getSettings() {
$result = $database->query('SELECT * FROM lychee_settings;');
while($row = $result->fetch_object()) {
$return[$row->key] = $row->value;
$return[$row->key] = $row->value;
}
return $return;
@ -66,22 +66,18 @@ function setPassword($password) {
}
/*function setCheckForUpdates() {
function setDropboxKey($key) {
global $database;
$result = $database->query("SELECT value FROM lychee_settings WHERE `key` = 'checkForUpdates';");
$row = $result->fetch_object();
if (strlen($key)<1||strlen($key)>50) return false;
if ($row->value==0) $checkForUpdates = 1;
else $checkForUpdates = 0;
$result = $database->query("UPDATE lychee_settings SET value = '$checkForUpdates' WHERE `key` = 'checkForUpdates';");
$result = $database->query("UPDATE lychee_settings SET value = '$key' WHERE `key` = 'dropboxKey';");
if (!$result) return false;
return true;
}*/
}
function setSorting($type, $order) {

@ -1,75 +1,80 @@
<?php
/**
* @name Upload Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @name Upload Module
* @author Philipp Maurer
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
function upload($files, $albumID) {
global $database;
global $database, $settings;
switch($albumID) {
// s for public (share)
case 's':
$public = 1;
$star = 0;
$albumID = 0;
break;
// f for starred (fav)
case 'f':
$star = 1;
$public = 0;
$albumID = 0;
break;
default:
$star = 0;
$public = 0;
case 's':
$public = 1;
$star = 0;
$albumID = 0;
break;
// f for starred (fav)
case 'f':
$star = 1;
$public = 0;
$albumID = 0;
break;
default:
$star = 0;
$public = 0;
}
foreach ($files as $file) {
$id = str_replace('.', '', microtime(true));
while(strlen($id)<14) $id .= 0;
$tmp_name = $file["tmp_name"];
if ($file['type']!=='image/jpeg'&&
$file['type']!=='image/png'&&
$file['type']!=='image/gif')
return false;
$type = getimagesize($tmp_name);
if (($type[2]!=1)&&($type[2]!=2)&&($type[2]!=3)) return false;
$data = array_reverse(explode('.', $file["name"]));
$data = $data[0];
$id = str_replace('.', '', microtime(true));
while(strlen($id)<14) $id .= 0;
$photo_name = md5($id) . ".$data";
$tmp_name = $file['tmp_name'];
$extension = array_reverse(explode('.', $file['name']));
$extension = $extension[0];
$photo_name = md5($id) . ".$extension";
// Import if not uploaded via web
if (!is_uploaded_file($tmp_name)) {
if (copy($tmp_name, "../uploads/big/" . $photo_name)) {
unlink($tmp_name);
// Import if not uploaded via web
if (!is_uploaded_file($tmp_name)) {
if (copy($tmp_name, '../uploads/big/' . $photo_name)) {
@unlink($tmp_name);
$import_name = $tmp_name;
}
} else {
move_uploaded_file($tmp_name, "../uploads/big/" . $photo_name);
$import_name = "";
}
} else {
move_uploaded_file($tmp_name, '../uploads/big/' . $photo_name);
$import_name = '';
}
// Read infos
$info = getInfo($photo_name);
// Read infos
$info = getInfo($photo_name);
// Use title of file if IPTC title missing
if ($info['title']==='')
$info['title'] = mysqli_real_escape_string($database, substr(basename($file['name'], ".$extension"), 0, 30));
// Set orientation based on EXIF data
if (isset($info['orientation'])&&isset($info['width'])&&isset($info['height'])) {
// Set orientation based on EXIF data
if ($file['type']==='image/jpeg'&&isset($info['orientation'])&&isset($info['width'])&&isset($info['height'])) {
if ($info['orientation']==3||$info['orientation']==6||$info['orientation']==8) {
if ($info['orientation']==3||$info['orientation']==6||$info['orientation']==8) {
$newWidth = $info['width'];
$newHeight = $info['height'];
$newWidth = $info['width'];
$newHeight = $info['height'];
$sourceImg = imagecreatefromjpeg("../uploads/big/$photo_name");
$sourceImg = imagecreatefromjpeg("../uploads/big/$photo_name");
switch($info['orientation']){
switch($info['orientation']){
case 2:
// mirror
@ -83,77 +88,77 @@ function upload($files, $albumID) {
case 4:
// rotate 180 and mirror
// not yet implemented
break;
break;
case 5:
// rotate 90 and mirror
// not yet implemented
break;
break;
case 6:
$sourceImg = imagerotate($sourceImg, -90, 0);
$newWidth = $info['height'];
$newHeight = $info['width'];
break;
break;
case 7:
// rotate -90 and mirror
// not yet implemented
break;
break;
case 8:
$sourceImg = imagerotate($sourceImg, 90, 0);
$newWidth = $info['height'];
$newHeight = $info['width'];
break;
}
$newSourceImg = imagecreatetruecolor($newWidth, $newHeight);
imagecopyresampled($newSourceImg, $sourceImg, 0, 0, 0, 0, $newWidth, $newHeight, $newWidth, $newHeight);
imagejpeg($newSourceImg, "../uploads/big/$photo_name", 100);
}
}
// Create Thumb
if (!createThumb($photo_name)) return false;
// Save to DB
$query = "INSERT INTO lychee_photos (id, title, url, description, type, width, height, size, sysdate, systime, iso, aperture, make, model, shutter, focal, takedate, taketime, thumbUrl, album, public, star, import_name)
VALUES (
'" . $id . "',
'" . $info['title'] . "',
'" . $photo_name . "',
'" . $info['description'] . "',
'" . $info['type'] . "',
'" . $info['width'] . "',
'" . $info['height'] . "',
'" . $info['size'] . "',
'" . $info['date'] . "',
'" . $info['time'] . "',
'" . $info['iso'] . "',
'" . $info['aperture'] . "',
'" . $info['make'] . "',
'" . $info['model'] . "',
'" . $info['shutter'] . "',
'" . $info['focal'] . "',
'" . $info['takeDate'] . "',
'" . $info['takeTime'] . "',
'" . md5($id) . ".jpeg',
'" . $albumID . "',
'" . $public . "',
'" . $star . "',
'" . $import_name . "');";
$result = $database->query($query);
if (!$result) return false;
}
return true;
break;
}
$newSourceImg = imagecreatetruecolor($newWidth, $newHeight);
imagecopyresampled($newSourceImg, $sourceImg, 0, 0, 0, 0, $newWidth, $newHeight, $newWidth, $newHeight);
imagejpeg($newSourceImg, "../uploads/big/$photo_name", 100);
}
}
// Create Thumb
if (!createThumb($photo_name)) return false;
// Save to DB
$query = "INSERT INTO lychee_photos (id, title, url, description, type, width, height, size, sysdate, systime, iso, aperture, make, model, shutter, focal, takedate, taketime, thumbUrl, album, public, star, import_name)
VALUES (
'" . $id . "',
'" . $info['title'] . "',
'" . $photo_name . "',
'" . $info['description'] . "',
'" . $info['type'] . "',
'" . $info['width'] . "',
'" . $info['height'] . "',
'" . $info['size'] . "',
'" . $info['date'] . "',
'" . $info['time'] . "',
'" . $info['iso'] . "',
'" . $info['aperture'] . "',
'" . $info['make'] . "',
'" . $info['model'] . "',
'" . $info['shutter'] . "',
'" . $info['focal'] . "',
'" . $info['takeDate'] . "',
'" . $info['takeTime'] . "',
'" . md5($id) . ".jpeg',
'" . $albumID . "',
'" . $public . "',
'" . $star . "',
'" . $import_name . "');";
$result = $database->query($query);
if (!$result) return false;
}
return true;
}
@ -161,16 +166,16 @@ function getInfo($filename) {
global $database;
$url = '../uploads/big/' . $filename;
$iptcArray = array();
$info = getimagesize($url, $iptcArray);
$url = '../uploads/big/' . $filename;
$iptcArray = array();
$info = getimagesize($url, $iptcArray);
// General information
$return['type'] = $info['mime'];
$return['width'] = $info[0];
$return['height'] = $info[1];
$return['date'] = date('d.m.Y', filectime($url));
$return['time'] = date('H:i:s', filectime($url));
$return['type'] = $info['mime'];
$return['width'] = $info[0];
$return['height'] = $info[1];
$return['date'] = date('d.m.Y', filectime($url));
$return['time'] = date('H:i:s', filectime($url));
// Size
$size = filesize($url)/1024;
@ -178,76 +183,78 @@ function getInfo($filename) {
else $return['size'] = round($size, 1) . ' KB';
// IPTC Metadata Fallback
$return['title'] = '';
$return['description'] = '';
$return['title'] = '';
$return['description'] = '';
// IPTC Metadata
if(isset($iptcArray['APP13'])) {
$iptcInfo = iptcparse($iptcArray['APP13']);
if (is_array($iptcInfo)) {
$temp = $iptcInfo['2#105'][0];
$temp = @$iptcInfo['2#105'][0];
if (isset($temp)&&strlen($temp)>0) $return['title'] = $temp;
$temp = $iptcInfo['2#120'][0];
$temp = @$iptcInfo['2#120'][0];
if (isset($temp)&&strlen($temp)>0) $return['description'] = $temp;
}
}
// EXIF Metadata Fallback
$return['orientation'] = '';
$return['iso'] = '';
$return['aperture'] = '';
$return['make'] = '';
$return['model'] = '';
$return['shutter'] = '';
$return['focal'] = '';
$return['takeDate'] = '';
$return['takeTime'] = '';
$return['orientation'] = '';
$return['iso'] = '';
$return['aperture'] = '';
$return['make'] = '';
$return['model'] = '';
$return['shutter'] = '';
$return['focal'] = '';
$return['takeDate'] = '';
$return['takeTime'] = '';
// Read EXIF
if ($info['mime']=='image/jpeg') $exif = exif_read_data($url, 'EXIF', 0);
else $exif = false;
// EXIF Metadata
if ($info['mime']=='image/jpeg'&&function_exists('exif_read_data')&&@exif_read_data($url, 'EXIF', 0)) {
$exif = exif_read_data($url, 'EXIF', 0);
if ($exif!==false) {
$temp = $exif['Orientation'];
if (isset($temp)) $return['orientation'] = $temp;
$temp = @$exif['Orientation'];
if (isset($temp)) $return['orientation'] = $temp;
$temp = $exif['ISOSpeedRatings'];
if (isset($temp)) $return['iso'] = $temp;
$temp = @$exif['ISOSpeedRatings'];
if (isset($temp)) $return['iso'] = $temp;
$temp = $exif['COMPUTED']['ApertureFNumber'];
if (isset($temp)) $return['aperture'] = $temp;
$temp = @$exif['COMPUTED']['ApertureFNumber'];
if (isset($temp)) $return['aperture'] = $temp;
$temp = $exif['Make'];
if (isset($temp)) $return['make'] = $exif['Make'];
$temp = @$exif['Make'];
if (isset($temp)) $return['make'] = $exif['Make'];
$temp = $exif['Model'];
if (isset($temp)) $return['model'] = $temp;
$temp = @$exif['Model'];
if (isset($temp)) $return['model'] = $temp;
$temp = $exif['ExposureTime'];
if (isset($temp)) $return['shutter'] = $exif['ExposureTime'] . ' Sec.';
$temp = @$exif['ExposureTime'];
if (isset($temp)) $return['shutter'] = $exif['ExposureTime'] . ' Sec.';
$temp = $exif['FocalLength'];
if (isset($temp)) $return['focal'] = ($temp/1) . ' mm';
$temp = @$exif['FocalLength'];
if (isset($temp)) $return['focal'] = ($temp/1) . ' mm';
$temp = $exif['DateTimeOriginal'];
if (isset($temp)) {
$exifDate = explode(' ', $temp);
$date = explode(':', $exifDate[0]);
$return['takeDate'] = $date[2].'.'.$date[1].'.'.$date[0];
$return['takeTime'] = $exifDate[1];
}
$temp = @$exif['DateTimeOriginal'];
if (isset($temp)) {
$exifDate = explode(' ', $temp);
$date = explode(':', $exifDate[0]);
$return['takeDate'] = $date[2].'.'.$date[1].'.'.$date[0];
$return['takeTime'] = $exifDate[1];
}
}
}
// Security
foreach(array_keys($return) as $key) $return[$key] = mysqli_real_escape_string($database, $return[$key]);
return $return;
return $return;
}
@ -255,63 +262,61 @@ function createThumb($filename, $width = 200, $height = 200) {
global $settings;
$url = "../uploads/big/$filename";
$info = getimagesize($url);
$photoName = explode(".", $filename);
$newUrl = "../uploads/thumb/".$photoName[0].".jpeg";
$newUrl2x = "../uploads/thumb/".$photoName[0]."@2x.jpeg";
// Set position and size
$thumb = imagecreatetruecolor($width, $height);
$thumb2x = imagecreatetruecolor($width*2, $height*2);
if ($info[0]<$info[1]) {
$newSize = $info[0];
$startWidth = 0;
$startHeight = $info[1]/2 - $info[0]/2;
} else {
$newSize = $info[1];
$startWidth = $info[0]/2 - $info[1]/2;
$startHeight = 0;
}
// Fallback for older version
if ($info['mime']==='image/webp'&&floatval(phpversion())<5.5) return false;
// Create new image
switch($info['mime']) {
case 'image/jpeg': $sourceImg = imagecreatefromjpeg($url); break;
case 'image/png': $sourceImg = imagecreatefrompng($url); break;
case 'image/gif': $sourceImg = imagecreatefromgif($url); break;
case 'image/webp': $sourceImg = imagecreatefromwebp($url); break;
default: return false;
}
imagecopyresampled($thumb,$sourceImg,0,0,$startWidth,$startHeight,$width,$height,$newSize,$newSize);
imagecopyresampled($thumb2x,$sourceImg,0,0,$startWidth,$startHeight,$width*2,$height*2,$newSize,$newSize);
imagejpeg($thumb,$newUrl,$settings['thumbQuality']);
imagejpeg($thumb2x,$newUrl2x,$settings['thumbQuality']);
return true;
$url = "../uploads/big/$filename";
$info = getimagesize($url);
$photoName = explode(".", $filename);
$newUrl = "../uploads/thumb/$photoName[0].jpeg";
$newUrl2x = "../uploads/thumb/$photoName[0]@2x.jpeg";
// Set position and size
$thumb = imagecreatetruecolor($width, $height);
$thumb2x = imagecreatetruecolor($width*2, $height*2);
if ($info[0]<$info[1]) {
$newSize = $info[0];
$startWidth = 0;
$startHeight = $info[1]/2 - $info[0]/2;
} else {
$newSize = $info[1];
$startWidth = $info[0]/2 - $info[1]/2;
$startHeight = 0;
}
// Fallback for older version
if ($info['mime']==='image/webp'&&floatval(phpversion())<5.5) return false;
// Create new image
switch($info['mime']) {
case 'image/jpeg': $sourceImg = imagecreatefromjpeg($url); break;
case 'image/png': $sourceImg = imagecreatefrompng($url); break;
case 'image/gif': $sourceImg = imagecreatefromgif($url); break;
case 'image/webp': $sourceImg = imagecreatefromwebp($url); break;
default: return false;
}
imagecopyresampled($thumb,$sourceImg,0,0,$startWidth,$startHeight,$width,$height,$newSize,$newSize);
imagecopyresampled($thumb2x,$sourceImg,0,0,$startWidth,$startHeight,$width*2,$height*2,$newSize,$newSize);
imagejpeg($thumb,$newUrl,$settings['thumbQuality']);
imagejpeg($thumb2x,$newUrl2x,$settings['thumbQuality']);
return true;
}
function importPhoto($name, $albumID = 0) {
function importPhoto($path, $albumID = 0) {
$tmp_name = "../uploads/import/$name";
$info = getimagesize($tmp_name);
$size = filesize($tmp_name);
$nameFile = array(array());
$nameFile[0]['name'] = $name;
$nameFile[0]['type'] = $info['mime'];
$nameFile[0]['tmp_name'] = $tmp_name;
$nameFile[0]['error'] = 0;
$nameFile[0]['size'] = $size;
$info = getimagesize($path);
$size = filesize($path);
if (upload($nameFile, $albumID)) return true;
$nameFile = array(array());
$nameFile[0]['name'] = $path;
$nameFile[0]['type'] = $info['mime'];
$nameFile[0]['tmp_name'] = $path;
$nameFile[0]['error'] = 0;
$nameFile[0]['size'] = $size;
return false;
return upload($nameFile, $albumID);
}
@ -332,6 +337,7 @@ function importUrl($url, $albumID = 0) {
$pathinfo = pathinfo($key);
$filename = $pathinfo['filename'].".".$pathinfo['extension'];
$tmp_name = "../uploads/import/$filename";
copy($key, $tmp_name);
}
@ -351,8 +357,10 @@ function importUrl($url, $albumID = 0) {
$pathinfo = pathinfo($url);
$filename = $pathinfo['filename'].".".$pathinfo['extension'];
$tmp_name = "../uploads/import/$filename";
copy($url, $tmp_name);
return importPhoto($filename, $albumID);
return importPhoto($tmp_name, $albumID);
}
@ -362,23 +370,36 @@ function importUrl($url, $albumID = 0) {
}
function importServer($albumID = 0) {
function importServer($albumID = 0, $path = '../uploads/import/') {
global $database;
$i = 0;
$files = glob('../uploads/import/*');
$files = glob($path . '*');
$contains['photos'] = false;
$contains['albums'] = false;
foreach ($files as $file) {
if (@getimagesize($file)) {
if (!importPhoto(basename($file), $albumID)) return false;
$i++;
// Photo
if (!importPhoto($file, $albumID)) return false;
$contains['photos'] = true;
} else if (is_dir($file)) {
$name = mysqli_real_escape_string($database, basename($file));
$newAlbumID = addAlbum('[Import] ' . $name);
if ($newAlbumID!==false) importServer($newAlbumID, $file . '/');
$contains['albums'] = true;
}
}
if ($i===0) return "Warning: Folder empty!";
if ($contains['photos']===false&&$contains['albums']===false) return "Warning: Folder empty!";
if ($contains['photos']===false&&$contains['albums']===true) return "Notice: Import only contains albums!";
return true;
}

@ -1,12 +1,10 @@
<?php
/**
* @name check.php
* @author Philipp Maurer
* @name check.php
* @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich
* @description This file takes a look at your Lychee-configuration and displays all errors it can find.
* Everything should work if you can see the message 'Lychee is ready!'.
* @copyright 2014 by Tobias Reich
* @description This file takes a look at your Lychee-configuration and displays all errors it can find.
*/
define('LYCHEE', true);
@ -16,50 +14,52 @@ header('content-type: text/plain');
$error = '';
// Include
if (!file_exists('../php/config.php')) exit('Error 001: Configuration not found. Please install Lychee first.');
require('../php/config.php');
if (!file_exists('../data/config.php')) exit('Error 001: Configuration not found. Please install Lychee first.');
require('../data/config.php');
require('../php/modules/settings.php');
// Database
$database = new mysqli($dbHost, $dbUser, $dbPassword, $dbName);
if (mysqli_connect_errno()!=0) $error .= ('Error 100: ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . '' . PHP_EOL);
if (mysqli_connect_errno()!=0) $error .= ('Error 100: ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . '' . PHP_EOL);
// Get Settings
$settings = getSettings();
// PHP Version
if (floatval(phpversion())<5.2) $error .= ('Error 200: Please upgrade to PHP 5.2 or higher!' . PHP_EOL);
if (floatval(phpversion())<5.2) $error .= ('Error 200: Please upgrade to PHP 5.2 or higher!' . PHP_EOL);
// Extensions
if (!extension_loaded('exif')) $error .= ('Error 300: PHP exif extension not activated' . PHP_EOL);
if (!extension_loaded('mbstring')) $error .= ('Error 301: PHP mbstring extension not activated' . PHP_EOL);
if (!extension_loaded('gd')) $error .= ('Error 302: PHP gd extension not activated' . PHP_EOL);
if (!extension_loaded('mysqli')) $error .= ('Error 303: PHP mysqli extension not activated' . PHP_EOL);
if (!extension_loaded('exif')) $error .= ('Error 300: PHP exif extension not activated' . PHP_EOL);
if (!extension_loaded('mbstring')) $error .= ('Error 301: PHP mbstring extension not activated' . PHP_EOL);
if (!extension_loaded('gd')) $error .= ('Error 302: PHP gd extension not activated' . PHP_EOL);
if (!extension_loaded('mysqli')) $error .= ('Error 303: PHP mysqli extension not activated' . PHP_EOL);
if (!extension_loaded('json')) $error .= ('Error 304: PHP json extension not activated' . PHP_EOL);
// Config
if (!isset($dbName)||$dbName=='') $error .= ('Error 400: No property for $dbName in config.php' . PHP_EOL);
if (!isset($dbUser)||$dbUser=='') $error .= ('Error 401: No property for $dbUser in config.php' . PHP_EOL);
if (!isset($dbPassword)) $error .= ('Error 402: No property for $dbPassword in config.php' . PHP_EOL);
if (!isset($dbHost)||$dbHost=='') $error .= ('Error 403: No property for $dbHost in config.php' . PHP_EOL);
if (!isset($dbName)||$dbName=='') $error .= ('Error 400: No property for $dbName in config.php' . PHP_EOL);
if (!isset($dbUser)||$dbUser=='') $error .= ('Error 401: No property for $dbUser in config.php' . PHP_EOL);
if (!isset($dbPassword)) $error .= ('Error 402: No property for $dbPassword in config.php' . PHP_EOL);
if (!isset($dbHost)||$dbHost=='') $error .= ('Error 403: No property for $dbHost in config.php' . PHP_EOL);
// Database Config
if (!$settings['username']||$settings['username']=='') $error .= ('Error 404: Username empty or not set' . PHP_EOL);
if (!$settings['password']||$settings['password']=='') $error .= ('Error 405: Password empty or not set' . PHP_EOL);
if (!$settings['username']||$settings['username']=='') $error .= ('Error 404: Username empty or not set' . PHP_EOL);
if (!$settings['password']||$settings['password']=='') $error .= ('Error 405: Password empty or not set' . PHP_EOL);
if (!$settings['thumbQuality']||$settings['thumbQuality']=='') $error .= ('Error 407: No or wrong property for thumbQuality' . PHP_EOL);
if (!$settings['sorting']||$settings['sorting']=='') $error .= ('Error 408: Wrong property for sorting' . PHP_EOL);
if (!$settings['dropboxKey']) $error .= ('Error 409: No property for dropboxKey' . PHP_EOL);
if (!$settings['checkForUpdates']||($settings['checkForUpdates']!='0'&&$settings['checkForUpdates']!='1')) $error .= ('Error 406: No or wrong property for checkForUpdates' . PHP_EOL);
if (!$settings['thumbQuality']||$settings['thumbQuality']=='') $error .= ('Error 407: No or wrong property for thumbQuality' . PHP_EOL);
if (!$settings['sorting']||$settings['sorting']=='') $error .= ('Error 408: Wrong property for sorting' . PHP_EOL);
// Permissions
if (substr(sprintf('%o', @fileperms('../uploads/big/')), -4)!='0777') $error .= ('Error 500: Wrong permissions for \'uploads/big\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/thumb/')), -4)!='0777') $error .= ('Error 501: Wrong permissions for \'uploads/thumb\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/import/')), -4)!='0777') $error .= ('Error 502: Wrong permissions for \'uploads/import\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/')), -4)!='0777') $error .= ('Error 503: Wrong permissions for \'uploads/\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../php/')), -4)!='0777') $error .= ('Error 504: Wrong permissions for \'php/\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/big/')), -4)!='0777') $error .= ('Error 500: Wrong permissions for \'uploads/big\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/thumb/')), -4)!='0777') $error .= ('Error 501: Wrong permissions for \'uploads/thumb\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/import/')), -4)!='0777')$error .= ('Error 502: Wrong permissions for \'uploads/import\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/')), -4)!='0777') $error .= ('Error 503: Wrong permissions for \'uploads/\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../data/')), -4)!='0777') $error .= ('Error 504: Wrong permissions for \'data/\' (777 required)' . PHP_EOL);
if ($error=='') echo('Lychee is ready. Lets rock!' . PHP_EOL . PHP_EOL); else echo $error;
if ($error=='') echo('Everything is fine. Lychee should work without problems!' . PHP_EOL . PHP_EOL); else echo $error;
// Check php.ini Settings
if (ini_get('max_execution_time')<200&&ini_set('upload_max_filesize', '20M')!==true) echo('Warning: You may experience problems when uploading a large amount of photos. Take a look in the FAQ for details.' . PHP_EOL);
if (ini_get('max_execution_time')<200&&ini_set('upload_max_filesize', '20M')===false) echo('Warning: You may experience problems when uploading a large amount of photos. Take a look in the FAQ for details.' . PHP_EOL);
// 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);

@ -9,7 +9,7 @@ Lychee is a free photo-management tool, which runs on your server or web-space.
## Installation
To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database. Follow the instructions to install Lychee on your server. [Installation &#187;](docs/md/Installation.md)
To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database. Follow the instructions to install Lychee on your server. [Installation &#187;](docs/Installation.md)
## How to use
@ -17,20 +17,23 @@ You can use Lychee right after the installation. Here are some advanced features
### Settings
Sign in and click the gear on the top left corner to change your settings. If you want to edit them manually: MySQL details are stored in `php/config.php`. Other options and settings are stored directly in the database. [Settings &#187;](docs/md/Settings.md)
Sign in and click the gear on the top left corner to change your settings. If you want to edit them manually: MySQL details are stored in `data/config.php`. Other options and hidden settings are stored directly in the database. [Settings &#187;](docs/Settings.md)
### Update
1. Replace all files, excluding `uploads/`
2. Open Lychee and enter your database details
Updating is as easy as it should be. [Update &#187;](docs/Update.md)
### FTP Upload
### Build
You can import photos from your server or upload photos directly with every FTP client into Lychee. [FTP Upload &#187;](docs/md/FTP Upload.md)
Lychee is ready to use, right out of the box. If you want to contribute and edit CSS or JS files, you need to rebuild Lychee. [Build &#187;](docs/Build.md)
### Keyboard Shortcuts
These shortcuts will help you to use Lychee even faster. [Keyboard Shortcuts &#187;](docs/md/Keyboard Shortcuts.md)
These shortcuts will help you to use Lychee even faster. [Keyboard Shortcuts &#187;](docs/Keyboard Shortcuts.md)
### Dropbox import
In order to use the Dropbox import from your server, you need a valid drop-ins app key from [their website](https://www.dropbox.com/developers/apps/create). Lychee will ask you for this key, the first time you try to use the import. Want to change your code? Take a loot at [the settings](docs/Settings.md) of Lychee.
### Twitter Cards
@ -38,7 +41,7 @@ Lychee supports [Twitter Cards](https://dev.twitter.com/docs/cards) and [Open Gr
## Troubleshooting
Take a look at the [FAQ](docs/md/FAQ.md) if you have problems.
Take a look at the [FAQ](docs/FAQ.md) if you have problems.
## Extensions
@ -53,7 +56,11 @@ Take a look at the [FAQ](docs/md/FAQ.md) if you have problems.
| 1.2, 1.3, 2.x | [Tobias Reich](http://electerious.com)|
| 1.0, 1.1 | [Tobias Reich](http://electerious.com)<br>[Philipp Maurer](http://phinal.net) |
##License
## 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.
## License
(MIT License)
@ -64,4 +71,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -9,10 +9,9 @@
<meta name="keywords" content="">
<meta name="description" content="">
<link type="text/css" rel="stylesheet" href="assets/css/min/reset.css">
<link type="text/css" rel="stylesheet" href="assets/css/min/main.css">
<link type="text/css" rel="stylesheet" href="assets/build/main.css">
<link rel="shortcut icon" href="assets/img/favicon.ico">
<link rel="shortcut icon" href="favicon.ico">
<meta name="apple-mobile-web-app-status-bar-style" content="black" >
<meta name="viewport" content="user-scalable=no, initial-scale=1">
@ -24,7 +23,7 @@
define("LYCHEE", true);
require("php/config.php");
require("data/config.php");
require("php/modules/db.php");
require("php/modules/misc.php");
@ -57,10 +56,9 @@
<div id="infobox"></div>
<!-- JS -->
<script type="text/javascript" src="assets/js/min/frameworks.js"></script>
<script type="text/javascript" src="assets/js/modules/build.js"></script>
<script type="text/javascript" src="assets/js/view.js"></script>
<script type="text/javascript" src="assets/js/_frameworks.js"></script>
<script type="text/javascript" src="assets/js/build.js"></script>
<script type="text/javascript" src="assets/js/view/main.js"></script>
</body>
</html>
Loading…
Cancel
Save