diff --git a/.gitignore b/.gitignore index 5b977a3..3c060d6 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,8 @@ lib # intellij files *.iml -.idea \ No newline at end of file +.idea + +# test folders +test/folder1 +test/folder2 \ No newline at end of file diff --git a/docs/TorrentLibrary.html b/docs/TorrentLibrary.html index 2bf6486..0801abc 100644 --- a/docs/TorrentLibrary.html +++ b/docs/TorrentLibrary.html @@ -24,7 +24,7 @@
@@ -103,7 +103,7 @@

new Tor
Source:
@@ -219,7 +219,7 @@

(static)
Source:
@@ -283,7 +283,7 @@

(static) Source:
@@ -300,6 +300,85 @@

(static) + + + +
+

categoryForFile :Map

+ + + + +
+ Mapping filepath => category +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
Type:
+
    +
  • + +Map + + +
  • +
+ + + + + +
Example
+ +
{ "D:\somePath\Captain Russia The Summer Soldier (2014) 1080p BrRip x264.MKV" => TorrentLibrary.MOVIES_TYPE }
+ +
@@ -352,7 +431,7 @@

defaultPat
Source:
@@ -431,7 +510,7 @@

pathsSource:
@@ -510,7 +589,7 @@

storesSource:
@@ -597,7 +676,7 @@

(static)
Source:
@@ -715,7 +794,7 @@

addNewPath<
Source:
@@ -832,7 +911,7 @@

Returns:
- On success the promise will be resolved with "All paths were added!"
On error the promise will be rejected with an "Missing parameter" if the argument is missing
or "Cannot find/read a path" if one of the provided paths doesn't exist or is not readable
+ On success the promise will be resolved with "All paths were added!"
On error the promise will be rejected with an Error object "Missing parameter" if the argument is missing
or an Error object from fs
@@ -900,7 +979,7 @@

Source:
@@ -1000,7 +1079,7 @@

scanSource:
@@ -1061,7 +1140,7 @@

scan
- Generated by JSDoc 3.5.4 on Sat Aug 26 2017 02:36:48 GMT+0200 (Romance Daylight Time) using the Minami theme. + Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme.
diff --git a/docs/TorrentLibrary.js.html b/docs/TorrentLibrary.js.html index fad6bac..e7c1393 100644 --- a/docs/TorrentLibrary.js.html +++ b/docs/TorrentLibrary.js.html @@ -24,7 +24,7 @@
@@ -73,7 +73,7 @@

TorrentLibrary.js

/** * The variable where we store all kind of media files found in paths - * @typedef {Map.<string, {(TPN_Extended[]| Map.<string,TPN_Extended[]> )}>} StoreVar + * @typedef {Map.<string, {( Set<TPN_Extended>| Map.<string,Set<TPN_Extended>> )}>} StoreVar * @example * // An example of the variable after the scan method * [ @@ -107,16 +107,31 @@

TorrentLibrary.js

/** * module for exploring directories + * @external FileHound * @see {@link https://nspragg.github.io/filehound/} */ -import FileHound from 'filehound'; +import FileHound from 'filehound'; /** - * module fs from node - * @see {@link https://nodejs.org/api/fs.html} + * Access method from module fs (node) + * @external access + * @see {@link https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback} */ import {access} from 'fs'; +/** + * uniq method from Lodash + * @external uniq + * @see {@link https://lodash.com/docs/4.17.4#uniq} + */ +import {uniq} from 'lodash'; +/** + * difference method from lodash + * @external difference + * @see {@link https://lodash.com/docs/4.17.4#difference} + */ +import {difference} from 'lodash'; + /** * A promise object provided by the bluebird promise library. * @external Promise @@ -126,10 +141,25 @@

TorrentLibrary.js

/** * List of video file extensions + * @external videosExtension * @see {@link https://github.com/sindresorhus/video-extensions} */ import videosExtension from 'video-extensions'; +/** + * Parser for media files name + * @external nameParser + * @see {@link https://github.com/jy95/torrent-name-parser} + */ +import nameParser from 'torrent-name-parser' + +/** + * Constants for fs access + */ +import { + constants as FsConstants +} from 'fs' + import { EventEmitter } from 'events'; @@ -146,13 +176,17 @@

TorrentLibrary.js

* @since 0.0.0 * @return {string} */ - static get MOVIES_TYPE() { return "MOVIES" } + static get MOVIES_TYPE() { + return "MOVIES" + } /** * constant for tv series category * @return {string} */ - static get TV_SERIES_TYPE() { return "TV_SERIES"} + static get TV_SERIES_TYPE() { + return "TV_SERIES" + } /** * Create a TorrentLibrary @@ -179,9 +213,92 @@

TorrentLibrary.js

* @member {StoreVar} */ this.stores = new Map([ - [ TorrentLibrary.MOVIES_TYPE , [] ], - [ TorrentLibrary.TV_SERIES_TYPE, new Map()] - ]) + [TorrentLibrary.MOVIES_TYPE, new Set()], + [TorrentLibrary.TV_SERIES_TYPE, new Map()] + ]); + /** + * Mapping filepath => category + * @type {Map} + * @example + * { "D:\somePath\Captain Russia The Summer Soldier (2014) 1080p BrRip x264.MKV" => TorrentLibrary.MOVIES_TYPE } + */ + this.categoryForFile = new Map(); + /** + * Private method for adding new files + * @private + * @param files {string[]} An array of filePath + */ + this.addNewFiles = function (files) { + + // find the new files to be added + let alreadyFoundFiles = [...this.categoryForFile.keys()]; + let newFiles = difference(files, alreadyFoundFiles); + + // temp var for new files before adding them to stores var + let moviesSet = new Set(); + let tvSeriesSet = new Set(); + + // get previous result of stores var + let newMovies = this.stores.get(TorrentLibrary.MOVIES_TYPE); + let newTvSeries = this.stores.get(TorrentLibrary.TV_SERIES_TYPE); + + // process each file + for (let file of newFiles) { + // get data from nameParser lib + let jsonFile = nameParser(file); + // extend this object in order to be used by this library + Object.assign(jsonFile, {"filePath": file}); + // find out which type of this file + // if it has not undefined properties (season and episode) => TV_SERIES , otherwise MOVIE + let fileCategory = ( checkProperties(jsonFile, ["season", "episode"]) ) + ? TorrentLibrary.TV_SERIES_TYPE : TorrentLibrary.MOVIES_TYPE; + // add it in found files + this.categoryForFile.set(file, fileCategory); + // also in temp var + (fileCategory === TorrentLibrary.TV_SERIES_TYPE) ? tvSeriesSet.add(jsonFile) : moviesSet.add(jsonFile); + } + + // add the movies into newMovies + newMovies = new Set([...newMovies, ...moviesSet]); + + // add the tv series into newTvSeries + // First step : find all the series not in newTvSeries and add them to newTvSeries + difference( + uniq( + [...tvSeriesSet].map(function (tvSeries) { + return tvSeries.title; + }) + ), + ...newTvSeries.keys() + ).forEach(function (tvSeriesToInsert) { + newTvSeries.set(tvSeriesToInsert, new Set()); + }); + + // Second step : add the new files into the correct tvSeries Set + uniq( + [...tvSeriesSet].map(function (tvSeries) { + return tvSeries.title; + }) + ).forEach(function (tvSerie) { + + // get the current set for this tvSerie + let currentTvSerie = newTvSeries.get(tvSerie); + + // find all the episodes in the new one for this serie + let episodes = [...tvSeriesSet].filter(function (episode) { + return episode.title === tvSerie; + }); + + // add them and updates newTvSeries + newTvSeries.set(tvSerie, new Set([...currentTvSerie,...episodes])); + + }); + + // updates the stores var + this.stores.set(TorrentLibrary.MOVIES_TYPE, newMovies); + this.stores.set(TorrentLibrary.TV_SERIES_TYPE, newTvSeries); + + } } /** @@ -193,7 +310,7 @@

TorrentLibrary.js

* TorrentLibrary.listVideosExtension() * @static */ - static listVideosExtension(){ + static listVideosExtension() { return videosExtension; } @@ -205,26 +322,25 @@

TorrentLibrary.js

* // return resolved Promise "All paths were added!" * TorrentLibraryInstance.addNewPath("C:\Users\jy95\Desktop\New folder"); * @return {external:Promise} On success the promise will be resolved with "All paths were added!"<br> - * On error the promise will be rejected with an "Missing parameter" if the argument is missing<br> - * or "Cannot find/read a path" if one of the provided paths doesn't exist or is not readable<br> + * On error the promise will be rejected with an Error object "Missing parameter" if the argument is missing<br> + * or an Error object from fs <br> */ - addNewPath(...paths){ + addNewPath(...paths) { // the user should provide us at lest a path if (paths.length === 0) return missingParam(); let that = this; - return new PromiseLib(function (resolve,reject) { + return new PromiseLib(function (resolve, reject) { - return new PromiseLib.map(paths, function (path) { - // https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback - // check if directory exists and is readable - return access(path, fs.constants.F_OK | fs.constants.R_OK); + PromiseLib.map(paths, function (path) { + return access(path, FsConstants.F_OK | FsConstants.R_OK); }).then(function () { - that.paths = [...that.paths, ...paths]; + // keep only unique paths + that.paths = uniq([...that.paths, ...paths]); resolve("All paths were added!"); }).catch(e => { - reject("Cannot find/read a path"); + reject(e); }) }); @@ -236,7 +352,7 @@

TorrentLibrary.js

* @since 0.0.0 * @returns {boolean} */ - hasPathsProvidedByUser(){ + hasPathsProvidedByUser() { return this.paths.length === 0; } @@ -244,26 +360,42 @@

TorrentLibrary.js

* @todo Write the documentation. * @todo Implement this function. */ - scan(){ - /* - const files = FileHound.create() - .paths( (this.paths.length === 0) ? this.defaultPath : this.paths) + scan() { + + const foundFiles = FileHound.create() + .paths((this.paths.length === 0) ? this.defaultPath : this.paths) .ext(videosExtension) .find(); - */ - return null; + let that = this; + return new PromiseLib(function (resolve, reject) { + foundFiles + .then(function (files) { + that.addNewFiles(files); + resolve("Scanning completed"); + }) + .catch(function (err) { + reject(err); + }); + }); } } // rejected promise when someone doesn't provide function missingParam() { - return new PromiseLib(function (resolve,reject) { - reject("Missing parameter"); + return new PromiseLib(function (resolve, reject) { + reject(new Error("Missing parameter")); }); } +// check if an object has these properties and they are not undefined +function checkProperties(obj, properties) { + return properties.every(function (x) { + return x in obj && obj[x]; + }) +} + export default TorrentLibrary; @@ -276,7 +408,7 @@

TorrentLibrary.js


- Generated by JSDoc 3.5.4 on Sat Aug 26 2017 02:36:48 GMT+0200 (Romance Daylight Time) using the Minami theme. + Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme.
diff --git a/docs/external-FileHound.html b/docs/external-FileHound.html new file mode 100644 index 0000000..ec35014 --- /dev/null +++ b/docs/external-FileHound.html @@ -0,0 +1,148 @@ + + + + + + FileHound - Documentation + + + + + + + + + + + + + + + + + +
+ +

FileHound

+ + + + + + + +
+ +
+ +

+ FileHound +

+ + +
+ + + +
+ + + + +
+ +
+ +
+ Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme. +
+ + + + + \ No newline at end of file diff --git a/docs/external-Promise.html b/docs/external-Promise.html index 1174d52..9f556fa 100644 --- a/docs/external-Promise.html +++ b/docs/external-Promise.html @@ -24,7 +24,7 @@
@@ -87,7 +87,7 @@

Source:
@@ -139,7 +139,7 @@


- Generated by JSDoc 3.5.4 on Sat Aug 26 2017 02:36:48 GMT+0200 (Romance Daylight Time) using the Minami theme. + Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme.
diff --git a/docs/external-access.html b/docs/external-access.html new file mode 100644 index 0000000..4cd3115 --- /dev/null +++ b/docs/external-access.html @@ -0,0 +1,148 @@ + + + + + + access - Documentation + + + + + + + + + + + + + + + + + +
+ +

access

+ + + + + + + +
+ +
+ +

+ access +

+ + +
+ + + +
+ + + + +
+ +
+ +
+ Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme. +
+ + + + + \ No newline at end of file diff --git a/docs/external-difference.html b/docs/external-difference.html new file mode 100644 index 0000000..20c0ab9 --- /dev/null +++ b/docs/external-difference.html @@ -0,0 +1,148 @@ + + + + + + difference - Documentation + + + + + + + + + + + + + + + + + +
+ +

difference

+ + + + + + + +
+ +
+ +

+ difference +

+ + +
+ + + +
+ + + + +
+ +
+ +
+ Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme. +
+ + + + + \ No newline at end of file diff --git a/docs/external-nameParser.html b/docs/external-nameParser.html new file mode 100644 index 0000000..b26559a --- /dev/null +++ b/docs/external-nameParser.html @@ -0,0 +1,148 @@ + + + + + + nameParser - Documentation + + + + + + + + + + + + + + + + + +
+ +

nameParser

+ + + + + + + +
+ +
+ +

+ nameParser +

+ + +
+ + + +
+ + + + +
+ +
+ +
+ Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme. +
+ + + + + \ No newline at end of file diff --git a/docs/external-uniq.html b/docs/external-uniq.html new file mode 100644 index 0000000..7b102c5 --- /dev/null +++ b/docs/external-uniq.html @@ -0,0 +1,148 @@ + + + + + + uniq - Documentation + + + + + + + + + + + + + + + + + +
+ +

uniq

+ + + + + + + +
+ +
+ +

+ uniq +

+ + +
+ + + +
+ + + + +
+ +
+ +
+ Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme. +
+ + + + + \ No newline at end of file diff --git a/docs/external-videosExtension.html b/docs/external-videosExtension.html new file mode 100644 index 0000000..d492dd4 --- /dev/null +++ b/docs/external-videosExtension.html @@ -0,0 +1,148 @@ + + + + + + videosExtension - Documentation + + + + + + + + + + + + + + + + + +
+ +

videosExtension

+ + + + + + + +
+ +
+ +

+ videosExtension +

+ + +
+ + + +
+ + + + +
+ +
+ +
+ Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme. +
+ + + + + \ No newline at end of file diff --git a/docs/global.html b/docs/global.html index 61e8cc3..7afcf9c 100644 --- a/docs/global.html +++ b/docs/global.html @@ -24,7 +24,7 @@
@@ -175,7 +175,7 @@
Type:
  • -Map.<string, {(Array.<TPN_Extended>|Map.<string, Array.<TPN_Extended>>)}> +Map.<string, {(Set.<TPN_Extended>|Map.<string, Set.<TPN_Extended>>)}>
  • @@ -975,7 +975,7 @@
    Type:

    - Generated by JSDoc 3.5.4 on Sat Aug 26 2017 02:36:48 GMT+0200 (Romance Daylight Time) using the Minami theme. + Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme.
    diff --git a/docs/index.html b/docs/index.html index 28ece0a..51b6d65 100644 --- a/docs/index.html +++ b/docs/index.html @@ -24,7 +24,7 @@
    @@ -57,7 +57,7 @@
    - Generated by JSDoc 3.5.4 on Sat Aug 26 2017 02:36:48 GMT+0200 (Romance Daylight Time) using the Minami theme. + Generated by JSDoc 3.5.4 on Sat Aug 26 2017 19:02:13 GMT+0200 (Romance Daylight Time) using the Minami theme.
    diff --git a/package-lock.json b/package-lock.json index eb8a793..fd63b23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4122,6 +4122,9 @@ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, + "torrent-name-parser": { + "version": "git+https://github.com/jy95/torrent-name-parser.git#5f03a3e2a79276d3fd3368eb7161fa99bc33483a" + }, "tough-cookie": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", diff --git a/package.json b/package.json index f9ccb91..5c9fbc3 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,8 @@ "dependencies": { "bluebird": "^3.5.0", "filehound": "^1.16.2", + "lodash": "^4.17.4", + "torrent-name-parser": "git+https://github.com/jy95/torrent-name-parser.git", "video-extensions": "^1.1.0" } } diff --git a/src/TorrentLibrary.js b/src/TorrentLibrary.js index beaffca..ea36669 100644 --- a/src/TorrentLibrary.js +++ b/src/TorrentLibrary.js @@ -32,7 +32,7 @@ /** * The variable where we store all kind of media files found in paths - * @typedef {Map. )}>} StoreVar + * @typedef {Map.| Map.> )}>} StoreVar * @example * // An example of the variable after the scan method * [ @@ -66,16 +66,31 @@ /** * module for exploring directories + * @external FileHound * @see {@link https://nspragg.github.io/filehound/} */ -import FileHound from 'filehound'; +import FileHound from 'filehound'; /** - * module fs from node - * @see {@link https://nodejs.org/api/fs.html} + * Access method from module fs (node) + * @external access + * @see {@link https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback} */ import {access} from 'fs'; +/** + * uniq method from Lodash + * @external uniq + * @see {@link https://lodash.com/docs/4.17.4#uniq} + */ +import {uniq} from 'lodash'; +/** + * difference method from lodash + * @external difference + * @see {@link https://lodash.com/docs/4.17.4#difference} + */ +import {difference} from 'lodash'; + /** * A promise object provided by the bluebird promise library. * @external Promise @@ -85,10 +100,25 @@ import PromiseLib from 'bluebird' /** * List of video file extensions + * @external videosExtension * @see {@link https://github.com/sindresorhus/video-extensions} */ import videosExtension from 'video-extensions'; +/** + * Parser for media files name + * @external nameParser + * @see {@link https://github.com/jy95/torrent-name-parser} + */ +import nameParser from 'torrent-name-parser' + +/** + * Constants for fs access + */ +import { + constants as FsConstants +} from 'fs' + import { EventEmitter } from 'events'; @@ -105,13 +135,17 @@ class TorrentLibrary extends EventEmitter { * @since 0.0.0 * @return {string} */ - static get MOVIES_TYPE() { return "MOVIES" } + static get MOVIES_TYPE() { + return "MOVIES" + } /** * constant for tv series category * @return {string} */ - static get TV_SERIES_TYPE() { return "TV_SERIES"} + static get TV_SERIES_TYPE() { + return "TV_SERIES" + } /** * Create a TorrentLibrary @@ -138,9 +172,92 @@ class TorrentLibrary extends EventEmitter { * @member {StoreVar} */ this.stores = new Map([ - [ TorrentLibrary.MOVIES_TYPE , [] ], - [ TorrentLibrary.TV_SERIES_TYPE, new Map()] - ]) + [TorrentLibrary.MOVIES_TYPE, new Set()], + [TorrentLibrary.TV_SERIES_TYPE, new Map()] + ]); + /** + * Mapping filepath => category + * @type {Map} + * @example + * { "D:\somePath\Captain Russia The Summer Soldier (2014) 1080p BrRip x264.MKV" => TorrentLibrary.MOVIES_TYPE } + */ + this.categoryForFile = new Map(); + /** + * Private method for adding new files + * @private + * @param files {string[]} An array of filePath + */ + this.addNewFiles = function (files) { + + // find the new files to be added + let alreadyFoundFiles = [...this.categoryForFile.keys()]; + let newFiles = difference(files, alreadyFoundFiles); + + // temp var for new files before adding them to stores var + let moviesSet = new Set(); + let tvSeriesSet = new Set(); + + // get previous result of stores var + let newMovies = this.stores.get(TorrentLibrary.MOVIES_TYPE); + let newTvSeries = this.stores.get(TorrentLibrary.TV_SERIES_TYPE); + + // process each file + for (let file of newFiles) { + // get data from nameParser lib + let jsonFile = nameParser(file); + // extend this object in order to be used by this library + Object.assign(jsonFile, {"filePath": file}); + // find out which type of this file + // if it has not undefined properties (season and episode) => TV_SERIES , otherwise MOVIE + let fileCategory = ( checkProperties(jsonFile, ["season", "episode"]) ) + ? TorrentLibrary.TV_SERIES_TYPE : TorrentLibrary.MOVIES_TYPE; + // add it in found files + this.categoryForFile.set(file, fileCategory); + // also in temp var + (fileCategory === TorrentLibrary.TV_SERIES_TYPE) ? tvSeriesSet.add(jsonFile) : moviesSet.add(jsonFile); + } + + // add the movies into newMovies + newMovies = new Set([...newMovies, ...moviesSet]); + + // add the tv series into newTvSeries + // First step : find all the series not in newTvSeries and add them to newTvSeries + difference( + uniq( + [...tvSeriesSet].map(function (tvSeries) { + return tvSeries.title; + }) + ), + ...newTvSeries.keys() + ).forEach(function (tvSeriesToInsert) { + newTvSeries.set(tvSeriesToInsert, new Set()); + }); + + // Second step : add the new files into the correct tvSeries Set + uniq( + [...tvSeriesSet].map(function (tvSeries) { + return tvSeries.title; + }) + ).forEach(function (tvSerie) { + + // get the current set for this tvSerie + let currentTvSerie = newTvSeries.get(tvSerie); + + // find all the episodes in the new one for this serie + let episodes = [...tvSeriesSet].filter(function (episode) { + return episode.title === tvSerie; + }); + + // add them and updates newTvSeries + newTvSeries.set(tvSerie, new Set([...currentTvSerie,...episodes])); + + }); + + // updates the stores var + this.stores.set(TorrentLibrary.MOVIES_TYPE, newMovies); + this.stores.set(TorrentLibrary.TV_SERIES_TYPE, newTvSeries); + + } } /** @@ -152,7 +269,7 @@ class TorrentLibrary extends EventEmitter { * TorrentLibrary.listVideosExtension() * @static */ - static listVideosExtension(){ + static listVideosExtension() { return videosExtension; } @@ -164,26 +281,25 @@ class TorrentLibrary extends EventEmitter { * // return resolved Promise "All paths were added!" * TorrentLibraryInstance.addNewPath("C:\Users\jy95\Desktop\New folder"); * @return {external:Promise} On success the promise will be resolved with "All paths were added!"
    - * On error the promise will be rejected with an "Missing parameter" if the argument is missing
    - * or "Cannot find/read a path" if one of the provided paths doesn't exist or is not readable
    + * On error the promise will be rejected with an Error object "Missing parameter" if the argument is missing
    + * or an Error object from fs
    */ - addNewPath(...paths){ + addNewPath(...paths) { // the user should provide us at lest a path if (paths.length === 0) return missingParam(); let that = this; - return new PromiseLib(function (resolve,reject) { + return new PromiseLib(function (resolve, reject) { - return new PromiseLib.map(paths, function (path) { - // https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback - // check if directory exists and is readable - return access(path, fs.constants.F_OK | fs.constants.R_OK); + PromiseLib.map(paths, function (path) { + return access(path, FsConstants.F_OK | FsConstants.R_OK); }).then(function () { - that.paths = [...that.paths, ...paths]; + // keep only unique paths + that.paths = uniq([...that.paths, ...paths]); resolve("All paths were added!"); }).catch(e => { - reject("Cannot find/read a path"); + reject(e); }) }); @@ -195,7 +311,7 @@ class TorrentLibrary extends EventEmitter { * @since 0.0.0 * @returns {boolean} */ - hasPathsProvidedByUser(){ + hasPathsProvidedByUser() { return this.paths.length === 0; } @@ -203,23 +319,40 @@ class TorrentLibrary extends EventEmitter { * @todo Write the documentation. * @todo Implement this function. */ - scan(){ - /* - const files = FileHound.create() - .paths( (this.paths.length === 0) ? this.defaultPath : this.paths) + scan() { + + const foundFiles = FileHound.create() + .paths((this.paths.length === 0) ? this.defaultPath : this.paths) .ext(videosExtension) .find(); - */ - return null; + let that = this; + + return new PromiseLib(function (resolve, reject) { + foundFiles + .then(function (files) { + that.addNewFiles(files); + resolve("Scanning completed"); + }) + .catch(function (err) { + reject(err); + }); + }); } } // rejected promise when someone doesn't provide function missingParam() { - return new PromiseLib(function (resolve,reject) { - reject("Missing parameter"); + return new PromiseLib(function (resolve, reject) { + reject(new Error("Missing parameter")); }); } +// check if an object has these properties and they are not undefined +function checkProperties(obj, properties) { + return properties.every(function (x) { + return x in obj && obj[x]; + }) +} + export default TorrentLibrary; \ No newline at end of file diff --git a/test/APITests.js b/test/APITests.js index e3297c9..4de98a8 100644 --- a/test/APITests.js +++ b/test/APITests.js @@ -1,14 +1,53 @@ import TorrentLibrary from "../lib/TorrentLibrary"; import videosExtension from 'video-extensions'; import assert from "assert"; +import path from "path"; +import fs from "fs"; + +// just a cross plateform way to remove folder recursively +function deleteFolderRecursive(path) { + if (fs.existsSync(path)) { + fs.readdirSync(path).forEach(function (file, index) { + var curPath = path + "/" + file; + if (fs.lstatSync(curPath).isDirectory()) { // recurse + deleteFolderRecursive(curPath); + } else { // delete file + fs.unlinkSync(curPath); + } + }); + fs.rmdirSync(path); + } +} -describe("TorrentLibrary tests",function () { +describe("TorrentLibrary tests", function () { let libInstance; + let folders = [path.join(__dirname, "folder1"), path.join(__dirname, "folder2")]; + let files = [ + path.join(__dirname, "folder1", "The.Blacklist.S04E21.FRENCH.WEBRip.XviD.avi"), + path.join(__dirname, "folder2", "The.Blacklist.S04E14.FRENCH.WEBRip.XviD.avi"), + path.join(__dirname, "folder1", "Bad.Ass.2012.LiMiTED.TRUEFRENCH.DVDRiP.XviD-www.zone-telechargement.ws.avi") + ]; // initialization before(function () { libInstance = new TorrentLibrary(); + + // removes previously folders for test and recreate them + folders.forEach(function (folder) { + deleteFolderRecursive(folder); + fs.mkdir(folder, (err) => { + if (err) throw err; + }); + }); + + // create the files for scan methods + files.forEach(function (file) { + fs.writeFile(file, "", (err) => { + if (err) throw err; + }); + }); + }); describe("Static methods", function () { @@ -16,7 +55,7 @@ describe("TorrentLibrary tests",function () { context("listVideosExtension()", function () { it("should provide the same list of videos extensions", function () { - assert.deepEqual(JSON.stringify(videosExtension), JSON.stringify(TorrentLibrary.listVideosExtension()), "Not the same JSON" ); + assert.deepEqual(JSON.stringify(videosExtension), JSON.stringify(TorrentLibrary.listVideosExtension()), "Not the same JSON"); }); }); @@ -24,34 +63,64 @@ describe("TorrentLibrary tests",function () { context("Constants", function () { it("MOVIES_TYPE", function () { - assert.equal(TorrentLibrary.MOVIES_TYPE, "MOVIES", "Someone changed this constant value !"); + assert.equal(TorrentLibrary.MOVIES_TYPE, "MOVIES", "Someone changed this constant value !"); }); it("TV_SERIES_TYPE", function () { - assert.equal(TorrentLibrary.TV_SERIES_TYPE, "TV_SERIES", "Someone changed this constant value !"); + assert.equal(TorrentLibrary.TV_SERIES_TYPE, "TV_SERIES", "Someone changed this constant value !"); }); }); }); - describe("Instance Methods - To be implemented", function () { + describe("Instance Methods", function () { - /* context("addNewPath()", function () { - it("missing parameter",function (done) { - return libInstance.addNewPath() - .then( () => { + it("missing parameter", function (done) { + libInstance.addNewPath() + .then(() => { done(new Error("Missing parameter")); }) - .catch( (err) => { + .catch(() => { done(); }) - }) + }); + it("inexistent Path", function (done) { + libInstance.addNewPath(path.join(__dirname, "wrongPath")) + .then(() => { + done(new Error("This path should not exist or be readable")); + }) + .catch(() => { + done(); + }) + }); + + /* + it("existent paths", function (done) { + libInstance.addNewPath(folders) + .then(() => { + done() + }).catch((err) => { + done(err); + }) + }); + */ }); - */ + + context("scan()", function () { + this.timeout(10000); + + it("Must work without error", function (done) { + libInstance.scan().then(function () { + done(); + }).catch((err) => { + done(err); + }); + }); + }) });