├── .gitignore ├── .DS_Store ├── image ├── .DS_Store ├── toStar.png └── starred.png ├── Dockerfile ├── bower.json ├── package.json ├── server.js ├── routes └── rest.js ├── style └── app.css ├── services └── flickrService.js ├── index.html └── script └── app.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /node_modules 3 | /bower_components 4 | /data 5 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiJunpeng/flickr_gallery/HEAD/.DS_Store -------------------------------------------------------------------------------- /image/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiJunpeng/flickr_gallery/HEAD/image/.DS_Store -------------------------------------------------------------------------------- /image/toStar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiJunpeng/flickr_gallery/HEAD/image/toStar.png -------------------------------------------------------------------------------- /image/starred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiJunpeng/flickr_gallery/HEAD/image/starred.png -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6.3.1 2 | 3 | RUN npm install nodemon -g 4 | 5 | RUN mkdir -p /app 6 | 7 | WORKDIR /app 8 | 9 | ADD . /app 10 | 11 | RUN cd /app && npm install 12 | 13 | EXPOSE 3001 14 | 15 | CMD ["nodemon", "/app/server.js"] -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini_flcikr", 3 | "description": "", 4 | "main": "server.js", 5 | "license": "ISC", 6 | "homepage": "https://github.com/LiJunpeng/mini_flickr", 7 | "ignore": [ 8 | "**/.*", 9 | "node_modules", 10 | "bower_components", 11 | "test", 12 | "tests" 13 | ], 14 | "dependencies": { 15 | "angular-deckgrid": "^0.5.0", 16 | "me-lazyload": "^0.0.5" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini_flcikr", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bower": "^1.8.2", 14 | "express": "^4.14.0", 15 | "flickrapi": "^0.6.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | 4 | // var flickrService = require('./services/flickrService'); 5 | // flickrService.getRecentFlickrPhotos(function () { 6 | // var restRouter = require('./routes/rest'); 7 | 8 | // app.use('/', express.static(__dirname + '/')); 9 | // app.use('/api/v1', restRouter); 10 | 11 | // app.listen(3000); 12 | // console.log("Server initialized"); 13 | // }); 14 | 15 | 16 | var restRouter = require('./routes/rest'); 17 | 18 | app.use('/', express.static(__dirname + '/')); 19 | app.use('/api/v1', restRouter); 20 | 21 | app.listen(3001); 22 | console.log("Server initialized"); -------------------------------------------------------------------------------- /routes/rest.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | var flickrService = require('../services/flickrService'); 5 | 6 | router.get('/photos/', function (req, res) { 7 | //console.log(req.params.topic); 8 | var ip = req.headers['x-forwarded-for'] || 9 | req.connection.remoteAddress || 10 | req.socket.remoteAddress; 11 | console.log("Got a client request from " + ip); 12 | 13 | flickrService.getRecentFlickrPhotosWithTag(" ", function (recentPhotos) { 14 | res.json(recentPhotos); 15 | }); 16 | }); 17 | 18 | router.get('/photos/:topic', function (req, res) { 19 | //console.log(req.params.topic); 20 | var ip = req.headers['x-forwarded-for'] || 21 | req.connection.remoteAddress || 22 | req.socket.remoteAddress; 23 | console.log("Got a client request from " + ip); 24 | 25 | flickrService.getRecentFlickrPhotosWithTag(req.params.topic, function (recentPhotos) { 26 | res.json(recentPhotos); 27 | }); 28 | }); 29 | 30 | module.exports = router; -------------------------------------------------------------------------------- /style/app.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: 'Open Sans', sans-serif; 3 | } 4 | 5 | h1 { 6 | margin: 0; 7 | padding: 0; 8 | } 9 | 10 | h3 { 11 | margin: 0; 12 | padding: 10px; 13 | } 14 | 15 | img { 16 | width: 100%; 17 | } 18 | 19 | 20 | .pin-button-group{ 21 | margin: 50px 0 0 0; 22 | float: right 23 | } 24 | 25 | .pin-button { 26 | width: 77px; 27 | } 28 | 29 | .search-input-group { 30 | margin: -10px 0 0 0; 31 | } 32 | 33 | .search-input-group .search-addon { 34 | background: none; 35 | padding: 0; 36 | border: 0; 37 | } 38 | 39 | .search-input-group .search-button { 40 | border-left: 0; 41 | border-top-left-radius: 0; 42 | border-bottom-left-radius: 0; 43 | } 44 | 45 | .a-card { 46 | height: auto; 47 | border: 1px solid rgba(0, 0, 0, .15); 48 | border-radius: 3px; 49 | margin: 0 10px 10px 0; 50 | /*box-shadow: -2px 3px 3px #E8E8E8;*/ 51 | } 52 | 53 | .a-card-tags { 54 | padding: 0 10px 10px 10px; 55 | font-size: 80%; 56 | opacity: .5; 57 | word-wrap: break-word; 58 | } 59 | 60 | .a-card-pin { 61 | height: 30px; 62 | width: 32px; 63 | position: relative; 64 | left: 85%; 65 | } 66 | 67 | .a-card-pin-icon { 68 | background: url("images/starred.png") no-repeat; 69 | } 70 | 71 | .a-card-pin-icon:hover { 72 | background: url("images/toStar.png") no-repeat; 73 | } 74 | 75 | .deckgrid{ 76 | padding: 10px 0 10px 10px; 77 | } 78 | 79 | .deckgrid .column { 80 | float: left; 81 | } 82 | 83 | .deckgrid .column-1-1 { 84 | width: 100%; 85 | } 86 | 87 | .deckgrid .column-1-2 { 88 | width: 50%; 89 | } 90 | 91 | .deckgrid .column-1-3 { 92 | width: 33.33%; 93 | } 94 | 95 | .deckgrid .column-1-4 { 96 | width: 25%; 97 | } 98 | 99 | .deckgrid[deckgrid]::before { 100 | content: '4 .column.column-1-4'; 101 | font-size: 0; 102 | visibility: hidden; 103 | } 104 | 105 | #searchBox { 106 | margin-bottom: 20px; 107 | } 108 | 109 | @media screen and (max-width: 960px) { 110 | .deckgrid[deckgrid]::before { 111 | content: '3 .column.column-1-3'; 112 | } 113 | } 114 | 115 | @media screen and (max-width: 720px) { 116 | .deckgrid[deckgrid]::before { 117 | content: '2 .column.column-1-2'; 118 | } 119 | } 120 | 121 | @media screen and (max-width: 480px) { 122 | .deckgrid[deckgrid]::before { 123 | content: '1 .column.column-1-1'; 124 | } 125 | .pin-button-group{ 126 | float: left; 127 | } 128 | .search-input-group{ 129 | clear: left; 130 | } 131 | } -------------------------------------------------------------------------------- /services/flickrService.js: -------------------------------------------------------------------------------- 1 | var flickrApi = require('flickrapi'); 2 | var flickrOptions = { 3 | //put your flickr api key here 4 | api_key: "" 5 | }; 6 | 7 | // var recentPhotos = []; 8 | // var photoCount = 100; 9 | // var searchTag = 'mountain'; 10 | 11 | function getRecentFlickrPhotosWithTag(searchTag, callback) { 12 | var recentPhotos = []; 13 | var photoCount = 100; 14 | console.log(searchTag); 15 | 16 | flickrApi.tokenOnly(flickrOptions, function (err, flickr) { 17 | flickr.photos.search({tags: searchTag, page: 1, per_page: photoCount}, function (err, result) { 18 | if (err) { 19 | console.log(err); 20 | return; 21 | } 22 | var photos = result.photos.photo; 23 | var i = 0; 24 | photos.forEach(function (photo) { 25 | var title = photo.title; 26 | var link = composePhotoUrl(photo.owner, photo.id); 27 | var src = composePhotoSrc(photo); 28 | 29 | populateTags(flickr, photo.id, function (tags) { 30 | recentPhotos.push({ 31 | title: title, 32 | link: link, 33 | src: src, 34 | tags: tags, 35 | originalIndex: i++ 36 | }); 37 | if (recentPhotos.length == 100) { 38 | callback(recentPhotos); 39 | } 40 | }); 41 | }); 42 | }); 43 | }); 44 | 45 | } 46 | 47 | 48 | function getRecentFlickrPhotos(callback) { 49 | flickrApi.tokenOnly(flickrOptions, function (err, flickr) { 50 | flickr.photos.search({tags: searchTag, page: 1, per_page: photoCount}, function (err, result) { 51 | if (err) { 52 | console.log(err); 53 | return; 54 | } 55 | var photos = result.photos.photo; 56 | var i = 0; 57 | photos.forEach(function (photo) { 58 | var title = photo.title; 59 | var link = composePhotoUrl(photo.owner, photo.id); 60 | var src = composePhotoSrc(photo); 61 | 62 | populateTags(flickr, photo.id, function (tags) { 63 | recentPhotos.push({ 64 | title: title, 65 | link: link, 66 | src: src, 67 | tags: tags, 68 | originalIndex: i++ 69 | }); 70 | if (recentPhotos.length == 100) { 71 | return; 72 | } 73 | }); 74 | }); 75 | }); 76 | }); 77 | } 78 | 79 | function composePhotoUrl(userId, photoId) { 80 | //https://www.flickr.com/photos/12037949754@N01/155761353/ 81 | return 'https://www.flickr.com/photos/' + userId + '/' + photoId; 82 | } 83 | 84 | function composePhotoSrc(photo) { 85 | //https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}.jpg 86 | return 'https://farm' + photo.farm + '.staticflickr.com/' + photo.server + '/' + photo.id + '_' + photo.secret + '.jpg'; 87 | } 88 | 89 | function populateTags(flickr, photoId, callback) { 90 | flickr.photos.getInfo({photo_id: photoId}, function (err, result) { 91 | var rawTags = []; 92 | result.photo.tags.tag.forEach(function (tag) { 93 | rawTags.push(tag.raw); 94 | }); 95 | tags = rawTags.join(); 96 | callback(tags); 97 | }); 98 | } 99 | 100 | module.exports = { 101 | getRecentFlickrPhotosWithTag: getRecentFlickrPhotosWithTag, 102 | getRecentFlickrPhotos: getRecentFlickrPhotos 103 | }; 104 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |