├── .npmrc ├── .bowerrc ├── .gitignore ├── public ├── img │ └── bg.png ├── app │ ├── services │ │ ├── movie.js │ │ ├── subs.js │ │ ├── yts.js │ │ ├── favorites.js │ │ ├── tmdb.js │ │ └── movies │ │ │ └── mock.js │ ├── directives │ │ └── movie-collection │ │ │ └── movie-collection.js │ ├── controllers │ │ ├── nav.js │ │ ├── movies.js │ │ └── movie.js │ ├── filters │ │ └── capitalize.js │ ├── animations │ │ └── slide.js │ └── main.js └── css │ └── openflix.css ├── lib ├── routes │ ├── index.js │ ├── home.js │ └── views.js ├── views │ ├── movie-collection.jade │ ├── movies.jade │ ├── index.jade │ └── movie.jade └── errors │ ├── server.js │ └── index.js ├── .editorconfig ├── package.json ├── README.md ├── LICENSE ├── bower.json ├── .jshintrc └── server.js /.npmrc: -------------------------------------------------------------------------------- 1 | unsafe-perm = true -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "public/bower" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log 3 | node_modules 4 | public/bower/* 5 | -------------------------------------------------------------------------------- /public/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricardocasares/openflix/HEAD/public/img/bg.png -------------------------------------------------------------------------------- /lib/routes/index.js: -------------------------------------------------------------------------------- 1 | // exports 2 | exports.home = require('./home'); 3 | exports.views = require('./views'); -------------------------------------------------------------------------------- /public/app/services/movie.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('openflix') 3 | .service('movieService', function(tmDB, yts, subService) { 4 | 5 | 6 | }); 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /public/app/directives/movie-collection/movie-collection.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('openflix') 3 | .directive('movieCollection', function() { 4 | return { 5 | restrict: 'E', 6 | templateUrl: '/views/movie-collection', 7 | scope: { 8 | collection: '=' 9 | } 10 | }; 11 | }); 12 | -------------------------------------------------------------------------------- /lib/views/movie-collection.jade: -------------------------------------------------------------------------------- 1 | .container 2 | .row 3 | .col-xs-6.col-sm-4.col-md-3.col-lg-2(ng-if="movie.poster_path", ng-repeat="movie in collection") 4 | a(ng-href="/movies/{{ movie.title | slugify }}/{{movie.id}}").thumbnail 5 | img(ng-src="http://image.tmdb.org/t/p/w154{{movie.poster_path}}", title="{{movie.title}}").img-responsive 6 | -------------------------------------------------------------------------------- /public/app/controllers/nav.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('openflix') 3 | .controller('NavController', function($scope, MockMovieSvc, $location, $routeParams){ 4 | 5 | $scope.title = 'openflix'; 6 | 7 | $scope.genres = MockMovieSvc.getGenres(); 8 | 9 | $scope.search = function(query) { 10 | $location.path('/search/' + query); 11 | }; 12 | }); 13 | -------------------------------------------------------------------------------- /public/app/filters/capitalize.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('openflix') 3 | .filter('capitalize', function() { 4 | return function(input, all) { 5 | return (!!input) ? input.replace(/([^\W_]+[^\s-]*) */g, capitalize) : ''; 6 | }; 7 | 8 | function capitalize(txt) { 9 | return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /public/app/controllers/movies.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | angular 4 | .module('openflix') 5 | .controller('MoviesController', MoviesCtrl); 6 | 7 | MoviesCtrl.$inject = ['title', '$routeParams', 'collection']; 8 | 9 | function MoviesCtrl(title, $routeParams, collection) { 10 | var vm = this; 11 | vm.title = title; 12 | vm.movies = collection; 13 | vm.movies.active = 0; 14 | } 15 | })(); 16 | -------------------------------------------------------------------------------- /lib/routes/home.js: -------------------------------------------------------------------------------- 1 | // dependencies 2 | var router = require('express').Router(); 3 | var log = require('debug')('app:routes:home'); 4 | // routing 5 | router.get('/', index); 6 | /** 7 | * index 8 | * Renders home page 9 | * 10 | * @param {Object} req Current request 11 | * @param {Object} res Response 12 | * @return {Response} Response 13 | */ 14 | function index(req, res) { 15 | log('serving index'); 16 | res.render('index'); 17 | } 18 | // exports 19 | module.exports = router; -------------------------------------------------------------------------------- /lib/errors/server.js: -------------------------------------------------------------------------------- 1 | // exports 2 | module.exports = serverError; 3 | /** 4 | * serverError 5 | * Represents an error occured on the server 6 | * 7 | * @param {String} msg Error message 8 | */ 9 | function serverError(msg) { 10 | Error.call(this); 11 | Error.captureStackTrace(this, arguments.callee); 12 | this.message = msg; 13 | this.name = 'serverError'; 14 | this.status = 500; 15 | this.code = 1; 16 | } 17 | // use the Error prototype 18 | serverError.prototype.__proto__ = Error.prototype; -------------------------------------------------------------------------------- /public/app/services/subs.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('openflix') 3 | .service('subService', function($http, SSAPI) { 4 | var ss = {}; 5 | var apiKey = SSAPI; 6 | // base endpoint 7 | ss.base = 'http://jsonp.nodejitsu.com/?url=http://api.ysubs.com/subs/'; 8 | 9 | ss.get = function(imdb) { 10 | var url = ss.base + imdb; 11 | return $http.get(url) 12 | .success(function(subs){ 13 | return subs; 14 | }); 15 | }; 16 | 17 | return ss; 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /lib/routes/views.js: -------------------------------------------------------------------------------- 1 | // dependencies 2 | var router = require('express').Router(); 3 | var log = require('debug')('app:routes:views'); 4 | // routing 5 | router.get('/:template', renderTemplate); 6 | /** 7 | * renderTemplate 8 | * Renders a given template 9 | * 10 | * @param {Object} req Request object 11 | * @param {Object} res Response object 12 | * @return {Object} Response object 13 | */ 14 | function renderTemplate(req, res) { 15 | log('rendering %s.jade', req.params.template); 16 | return res.render(req.params.template); 17 | } 18 | // exports 19 | module.exports = router; -------------------------------------------------------------------------------- /public/app/animations/slide.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular 3 | .module('openflix') 4 | .animation('.slide', slideEffect); 5 | 6 | function slideEffect() { 7 | var NG_HIDE_CLASS = 'ng-hide'; 8 | return { 9 | beforeAddClass: function(element, className, done) { 10 | if (className === NG_HIDE_CLASS) { 11 | // element.slideUp(done); 12 | element.slideUp(done); 13 | } 14 | }, 15 | removeClass: function(element, className, done) { 16 | if (className === NG_HIDE_CLASS) { 17 | element.hide().slideDown(done); 18 | } 19 | } 20 | }; 21 | } -------------------------------------------------------------------------------- /public/app/services/yts.js: -------------------------------------------------------------------------------- 1 | angular.module('openflix') 2 | .service('yts', function($http) { 3 | 4 | var yts = {}; 5 | yts.base = 'https://yts.to/api/v2/'; 6 | 7 | yts.list = function() { 8 | return $http.get(yts.base + '/list.json', {cache: true}) 9 | .success(function(result){ 10 | return result.MovieList; 11 | }); 12 | }; 13 | 14 | yts.find = function(id) { 15 | return $http.get(yts.base + '/listimdb.json', { 16 | params: { 17 | imdb_id: id 18 | }, 19 | cache: true 20 | }) 21 | .success(function(result){ 22 | return result.MovieList; 23 | }); 24 | }; 25 | 26 | return yts; 27 | }); 28 | -------------------------------------------------------------------------------- /lib/views/movies.jade: -------------------------------------------------------------------------------- 1 | .carousel 2 | carousel(interval="5000") 3 | slide(ng-repeat="movie in mvVm.movies", active="movie.active", ng-if="movie.backdrop_path") 4 | img(ng-src="http://image.tmdb.org/t/p/w780/{{movie.backdrop_path}}") 5 | .carousel-caption 6 | h2 7 | a(href="/movies/{{ movie.title | slugify}}/{{movie.id}}") {{ movie.title }} 8 | p.movie-rating 9 | i.fa.fa-fw.fa-star 10 | | {{ movie.vote_average }}   11 | i.fa.fa-fw.fa-thumbs-up 12 | | {{ movie.vote_count }} 13 | 14 | .container.container-movie 15 | .row 16 | .col-lg-12 17 | h2.page-header {{ mvVm.title | capitalize}} 18 | 19 | movie-collection(collection="mvVm.movies") 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openflix", 3 | "version": "0.0.0", 4 | "description": "In browser torrent streaming netflix clone", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "postinstall": "./node_modules/.bin/bower install" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/ricardocasares/openflix.git" 13 | }, 14 | "keywords": [ 15 | "angular", 16 | "angularjs", 17 | "express", 18 | "expressjs", 19 | "boilerplate", 20 | "netflix", 21 | "clone" 22 | ], 23 | "author": "Ricardo Casares", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/ricardocasares/openflix/issues" 27 | }, 28 | "homepage": "https://github.com/ricardocasares/openflix", 29 | "dependencies": { 30 | "adm-zip": "^0.4.4", 31 | "body-parser": "^1.9.0", 32 | "bower": "^1.3.12", 33 | "debug": "^2.0.0", 34 | "express": "^4.9.5", 35 | "jade": "^1.7.0", 36 | "node-captions": "^0.2.6", 37 | "request": "^2.52.0" 38 | }, 39 | "devDependencies": { 40 | "wiredep": "^2.2.2" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | openflix 2 | ======== 3 | 4 | [![Join the chat at https://gitter.im/ricardocasares/openflix](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ricardocasares/openflix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | In browser torrent streaming open source netflix clone 7 | 8 | ## What we got so far 9 | * Demo: [openflix.rutapirata.com](http://openflix.rutapirata.com) 10 | * No streaming of any kind, just limited movie browsing and torrent fetching 11 | 12 | ## Todo 13 | * ~~Implement themoviedb.org to search & fetch film data~~ 14 | * ~~Implement yts.re/api to fetch torrent data~~ 15 | * Implement [webtorrent](https://github.com/feross/webtorrent) to accomplish in-browser torrent streaming 16 | * An alternative would be to implent this as a chrome extension [like this one](https://github.com/ricardocasares/bitford), downside: chrome-only 17 | * Implement yifysubtitles.com to fetch subs 18 | 19 | ## Wishlist 20 | * On-the-fly video/audio transcoding 21 | * Would be great, but I think it might be very slow 22 | * Maybe [videoconverter.js](http://bgrins.github.io/videoconverter.js) could help 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ricardo Casares 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boilerplate", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/ricardocasares/boilerplate", 5 | "authors": [ 6 | "Ricardo Casares " 7 | ], 8 | "description": "angular + express boilerplate", 9 | "keywords": [ 10 | "angular", 11 | "angularjs", 12 | "express", 13 | "expressjs", 14 | "boilerplate", 15 | "starter", 16 | "kit" 17 | ], 18 | "dependencies": { 19 | "angular": "~1.3.*", 20 | "angular-route": "~1.2.*", 21 | "bootstrap": "latest", 22 | "angular-loading-bar": "~0.6.0", 23 | "angular-animate": "~1.3.*", 24 | "jquery": "1.*", 25 | "fontawesome": "latest", 26 | "angular-resource": "~1.2.*", 27 | "angular-bootstrap": "~0.11.0", 28 | "angular-hotkeys": "chieffancypants/angular-hotkeys#~1.4.3", 29 | "angular-slugify": "~1.0.0", 30 | "ngstorage": "~0.3.0", 31 | "bootstrap-submenu": "~1.2.11" 32 | }, 33 | "license": "MIT", 34 | "private": true, 35 | "ignore": [ 36 | "**/.*", 37 | "node_modules", 38 | "bower_components", 39 | "test", 40 | "tests" 41 | ], 42 | "resolutions": { 43 | "angular": "~1.2.*" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /public/app/services/favorites.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('openflix') 3 | .service('favService', function($localStorage) { 4 | var fav = {}; 5 | $localStorage.favoritesCollection = $localStorage.favoritesCollection || []; 6 | 7 | fav.add = function(movie) { 8 | if(!fav.check(movie.imdb_id)) { 9 | $localStorage.favoritesCollection.push(movie); 10 | } 11 | }; 12 | 13 | fav.get = function() { 14 | return $localStorage.favoritesCollection; 15 | }; 16 | 17 | fav.remove = function(movie) { 18 | if(fav.check(movie.imdb_id)) { 19 | $localStorage.favoritesCollection = $localStorage.favoritesCollection.filter(function(obj) { 20 | return obj.imdb_id !== movie.imdb_id; 21 | }); 22 | } 23 | }; 24 | 25 | fav.check = function(imdbId) { 26 | var inFavs; 27 | if($localStorage.favoritesCollection.length === 0) { 28 | return false; 29 | } 30 | angular.forEach($localStorage.favoritesCollection, function(obj) { 31 | if(obj.imdb_id === imdbId) { 32 | inFavs = true; 33 | } else { 34 | inFavs = false; 35 | } 36 | }); 37 | return inFavs; 38 | }; 39 | 40 | return fav; 41 | 42 | }); 43 | -------------------------------------------------------------------------------- /public/app/controllers/movie.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular 3 | .module('openflix') 4 | .controller('MovieController', function($scope, movie, favService, $http){ 5 | // selected movie 6 | $scope.movie = movie; 7 | $scope.subtitleTracks = []; 8 | // torrent selection 9 | $scope.selectTorrent = function(id) { 10 | $scope.selectedTorrent = $scope.movie.torrents[id]; 11 | }; 12 | $scope.selectSubtitle = function(lang, idx) { 13 | $scope.selectedSubtitle = lang 14 | .substring(0,2) 15 | .toUpperCase() 16 | .concat(' ') 17 | .concat(idx + 1); 18 | $scope.downloadSubtitle(lang, idx); 19 | $scope.subtitles = true; 20 | }; 21 | 22 | $scope.downloadSubtitle = function(lang, idx) { 23 | var sub = $scope.movie.subtitles[lang][idx].url.split('/'); 24 | $scope.subtitleTracks = []; 25 | $scope.subtitleTracks.push({ 26 | url: '/api/subs/'+sub[2], 27 | srclang: lang.substring(0,2), 28 | label: lang 29 | }); 30 | }; 31 | 32 | $scope.addToFavs = function() { 33 | favService.add(movie); 34 | $scope.movie.inFavs = true; 35 | }; 36 | 37 | $scope.removeFromFavs = function() { 38 | favService.remove(movie); 39 | $scope.movie.inFavs = false; 40 | }; 41 | 42 | // set default torrent 43 | $scope.selectTorrent(0); 44 | $scope.selectSubtitle('english', 0); 45 | }); 46 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": false, 7 | "forin": true, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonbsp": true, 16 | "nonew": true, 17 | "plusplus": false, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": false, 21 | "strict": false, 22 | "maxparams": 10, 23 | "maxdepth": 5, 24 | "maxstatements": 40, 25 | "maxcomplexity": 8, 26 | "maxlen": 120, 27 | 28 | "asi": false, 29 | "boss": false, 30 | "debug": false, 31 | "eqnull": true, 32 | "esnext": false, 33 | "evil": false, 34 | "expr": true, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "iterator": false, 38 | "lastsemic": false, 39 | "laxbreak": false, 40 | "laxcomma": false, 41 | "loopfunc": true, 42 | "maxerr": false, 43 | "moz": false, 44 | "multistr": true, 45 | "notypeof": false, 46 | "proto": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "sub": true, 50 | "supernew": false, 51 | "validthis": false, 52 | "noyield": false, 53 | 54 | "browser": true, 55 | "node": true, 56 | 57 | "globals": { 58 | "angular": false, 59 | "$": false, 60 | "_": false, 61 | "moment": false 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | // dependencies 2 | var express = require('express'); 3 | var captions = require('node-captions'); 4 | var fs = require('fs'); 5 | var AdmZip = require('adm-zip'); 6 | var request = require('request'); 7 | var log = require('debug')('app:server'); 8 | // relative dependencies 9 | var errors = require('./lib/errors'); 10 | var routes = require('./lib/routes'); 11 | // app instance 12 | var app = express(); 13 | // app settings 14 | app.set('port', process.env.PORT || 3000); 15 | app.set('views', './lib/views'); 16 | app.set('view engine', 'jade'); 17 | app.use(express.static(__dirname + '/public')); 18 | // app modules 19 | app.use('/views', routes.views); 20 | app.get('/api/subs/:zip', function(req, res) { 21 | var url = 'http://www.yifysubtitles.com/subtitle-api/' + req.params.zip; 22 | request(url) 23 | .pipe(fs.createWriteStream('sub.zip')) 24 | .on('close', function () { 25 | var zip = new AdmZip('sub.zip'); 26 | fs.unlink('sub.zip'); 27 | var files = zip.getEntries(); 28 | files.forEach(function(file) { 29 | try { 30 | captions.srt.parse(file.getData(), function (err, data) { 31 | res.send(captions.vtt.generate(captions.srt.toJSON(data))); 32 | }); 33 | } catch(e) { 34 | console.log('Error getting subtitle file: ' + req.params.zip, e); 35 | } 36 | 37 | }); 38 | }); 39 | }); 40 | app.use('*', routes.home); 41 | // error handling 42 | app.use(errors.notFound); 43 | app.use(errors.defaultHandler); 44 | // start the server 45 | app.listen(app.get('port'), function() { 46 | log('started on port ' + app.get('port')); 47 | }); 48 | -------------------------------------------------------------------------------- /lib/errors/index.js: -------------------------------------------------------------------------------- 1 | var log = require('debug')('app:errors'); 2 | /** 3 | * logErrors 4 | * Logs errors to console while debugging 5 | * 6 | * @param {Error} err Error instance 7 | * @param {Object} req Request object 8 | * @param {Object} res Response object 9 | * @param {Function} next Next callback 10 | * @return {Function} Next callback 11 | */ 12 | exports.logErrors = function logErrors(err, req, res, next) { 13 | log(err.stack); 14 | return next(err); 15 | }; 16 | /** 17 | * notFound 18 | * Handles not found errors 19 | * 20 | * @param {Error} err Error object 21 | * @param {Request} req Request object 22 | * @param {Response} res Response object 23 | * @param {Function} next Next callback 24 | * @return {Response} Response object 25 | */ 26 | exports.notFound = function(req, res) { 27 | log('404 %s', req.path); 28 | var msg = { 29 | error: { 30 | msg: 'Resource not found', 31 | code: 0, 32 | status: 404 33 | } 34 | }; 35 | res.json(msg); 36 | }; 37 | /** 38 | * defaultHandler 39 | * Default error handler 40 | * 41 | * @param {Error} err Error object 42 | * @param {Request} req Request object 43 | * @param {Response} res Response object 44 | * @param {Function} next Next callback 45 | * @return {Response} Response object 46 | */ 47 | exports.defaultHandler = function defaultHandler(err, req, res, next) { 48 | log('error handled -> %s, stackTrace -> %s', err.message, err.stack); 49 | var msg = { 50 | error: { 51 | msg: err.message || 'Something went really wrong...', 52 | code: err.code, 53 | status: err.status || 500, 54 | stack: err.stack || 'test' 55 | } 56 | }; 57 | res.status(err.code || 500); 58 | res.json(msg); 59 | }; -------------------------------------------------------------------------------- /public/app/services/tmdb.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('openflix') 3 | .service('tmDB', function($http, TMDBAPI){ 4 | 5 | var tmDB = {}; 6 | var apiKey = TMDBAPI; 7 | 8 | tmDB.base = 'http://api.themoviedb.org/3'; 9 | 10 | tmDB.popular = function() { 11 | return $http.get(tmDB.base + '/movie/popular', { 12 | params: { 13 | api_key: apiKey, 14 | append_to_response: 'overview', 15 | } 16 | }) 17 | .success(function(popular){ 18 | return popular; 19 | }); 20 | }; 21 | 22 | tmDB.movie = function(id) { 23 | return $http.get(tmDB.base + '/movie/' + id, { 24 | params: { 25 | append_to_response: 'images', 26 | api_key: apiKey 27 | } 28 | }) 29 | .success(function(movie){ 30 | return movie; 31 | }); 32 | }; 33 | 34 | tmDB.genres = function() { 35 | return $http.get(tmDB.base + '/genre/movie/list', { 36 | params: { 37 | api_key: apiKey 38 | } 39 | }) 40 | .success(function(genres){ 41 | return genres; 42 | }); 43 | }; 44 | 45 | tmDB.genre = function(id) { 46 | return $http.get(tmDB.base + '/genre/' + id + '/movies', { 47 | params: { 48 | api_key: apiKey 49 | } 50 | }) 51 | .success(function(movies){ 52 | return movies; 53 | }); 54 | }; 55 | 56 | tmDB.search = function(query) { 57 | return $http.get(tmDB.base + '/search/movie', { 58 | params: { 59 | api_key: apiKey, 60 | query: query 61 | } 62 | }) 63 | .success(function(movies){ 64 | return movies; 65 | }); 66 | }; 67 | 68 | return tmDB; 69 | }); 70 | -------------------------------------------------------------------------------- /lib/views/index.jade: -------------------------------------------------------------------------------- 1 | doctype 2 | //if IE 8 3 | | 4 | //if gt IE 8 5 | |