1
0
Bläddra i källkod

добавил dao, запилил интерфейс

κρμγ 7 år sedan
förälder
incheckning
f90b74a5a4
22 ändrade filer med 263 tillägg och 62 borttagningar
  1. 0 16
      api.js
  2. 8 5
      backend.js
  3. 0 1
      cli.js
  4. 0 10
      modules/root.html
  5. 0 11
      modules/root.js
  6. 7 0
      src/api.js
  7. 12 8
      src/crawler.js
  8. 72 0
      src/dao.js
  9. 9 1
      src/db.js
  10. 0 0
      src/favicon.ico
  11. 2 2
      src/frontend.js
  12. 2 2
      src/global.css
  13. 1 1
      src/index.html
  14. 13 0
      src/nav/kfab.html
  15. 5 2
      src/nav/knav.html
  16. 11 1
      src/nav/knav.js
  17. 29 0
      src/root.html
  18. 21 0
      src/root.js
  19. 1 1
      src/route.js
  20. 1 1
      src/settings.js
  21. 0 0
      src/ui.js
  22. 69 0
      thirdparty/naturalSort.js

+ 0 - 16
api.js

@@ -1,16 +0,0 @@
-let ipc = require('electron').ipcMain;
-let SQL = require('./db.js');
-let _ = require('underscore');
-
-ipc.on('get:files', function (e, data) {
-    var res = Array.from(SQL.db.exec("SELECT * FROM files")).map(res => {
-        return Array.from(res.values).map(r => {
-            var x = {};
-            Array.from(res.columns).forEach((c, i) => {
-                x[c] = r[i]
-            });
-            return x;
-        })
-    });
-    e.sender.send('ok:files', !_.isEmpty(res) ? res[0] : []);
-});

+ 8 - 5
backend.js

@@ -1,5 +1,8 @@
-require('./settings.js');
-require('./db.js');
-require('./ui.js');
-require('./crawler.js');
-require('./api.js');
+require('./thirdparty/naturalSort.js');
+
+require('./src/settings.js');
+require('./src/db.js');
+require('./src/ui.js');
+require('./src/crawler.js');
+require('./src/api.js');
+require('./src/dao.js');

+ 0 - 1
cli.js

@@ -1,7 +1,6 @@
 #!/usr/bin/env node
 
 const electron = require('electron');
-const S = require('underscore.string');
 
 const proc = require('child_process');
 

+ 0 - 10
modules/root.html

@@ -1,10 +0,0 @@
-<div layout="column" class="main">
-    <knav></knav>
-    <md-content flex>
-        <md-list>
-            <md-list-item ng-repeat="f in files">
-                <div class="md-list-item-content">{{f.name}}</div>
-            </md-list-item>
-        </md-list>
-    </md-content>
-</div>

+ 0 - 11
modules/root.js

@@ -1,11 +0,0 @@
-let ipc = require('electron').ipcRenderer;
-require('angular').module('Ks').controller('RootController', function ($scope) {
-
-    $scope.files = [];
-
-    ipc.send('get:files');
-
-    ipc.on('ok:files', (e, data) => {
-        $scope.files = data;
-    })
-});

+ 7 - 0
src/api.js

@@ -0,0 +1,7 @@
+let ipc = require('electron').ipcMain;
+let _ = require('underscore');
+let fileRepo = require('./dao.js').FileRepo;
+
+ipc.on('get:files', function (e, data) {
+    e.sender.send('ok:files', fileRepo.findAll());
+});

+ 12 - 8
crawler.js → src/crawler.js

@@ -7,7 +7,7 @@ let S = require('underscore.string');
 let settings = require('./settings.js');
 let cheerio = require('cheerio');
 let request = require('request-promise-native');
-let SQL = require('./db.js');
+let fileRepo = require('./dao.js').FileRepo;
 
 if (settings().get('crawl') === undefined) settings().set('crawl', {});
 
@@ -44,7 +44,8 @@ function extractRows_v_0_1(fn) {
                     id: parseInt(S(al[0].attribs['href']).split('/')[2]),
                     dl: al[0].attribs['href'],
                     magnet: al[1].attribs['href'],
-                    name: al[3].children[0].data
+                    name: al[3].children[0].data,
+                    date: null
                 }
             }).forEach(fn)
         } catch (e) {
@@ -73,7 +74,10 @@ function doCrawl(force) {
                     return cheerio.load(body);
                 }
             }).then(function ($) {
-                extractRows(r => ret.push(r))($);
+                extractRows(r => {
+                    r.date = parseInt(date.format('x'));
+                    ret.push(r)
+                })($);
                 rs(ret);
             }, rj);
         })
@@ -87,13 +91,13 @@ function doCrawl(force) {
 
     var handler = function (res) {
         Array.from(res).forEach(r => {
+            r.otherId = r.id;
+            var old = fileRepo.findFirstByOtherId(r.otherId);
+            r.id = _.isObject(old) ? old.id : null;
             console.log(r);
-            if (_.isEmpty(SQL.db.exec(`SELECT * FROM files WHERE otherId = ${r.id}`)))
-                SQL.db.run("INSERT INTO files VALUES (NULL, ?, ?, ?)", [r.id, r.name, r.magnet]);
-            else
-                SQL.db.run("UPDATE files SET name = ?, magnet = ? WHERE files.otherId = ?", [r.name, r.magnet, r.id])
         });
-        SQL.commit();
+        fileRepo.save(res);
+        //fileRepo.commit();
 
         if (res.length == pageLength) {
             page = page + 1;

+ 72 - 0
src/dao.js

@@ -0,0 +1,72 @@
+let SQL = require('./db.js');
+let _ = require('underscore');
+
+function listResult(q) {
+    try {
+        var ret = Array.from(SQL.db.exec(q)).map(res => {
+            return Array.from(res.values).map(r => {
+                var x = {};
+                Array.from(res.columns).forEach((c, i) => {
+                    x[c] = r[i]
+                });
+                return x;
+            })
+        });
+        return !_.isEmpty(ret) ? ret[0] : [];
+    } catch (e) {
+        console.error(e);
+        throw e
+    }
+}
+
+class FileRepo {
+
+    findAll() {
+        return listResult('SELECT * FROM files')
+    }
+
+    findFirstByOtherId(otherId) {
+        return _.first(listResult(`SELECT * FROM files WHERE otherId = ${otherId}`))
+    }
+
+    exists(id) {
+        if (_.isUndefined(id) || _.isNull(id)) return false;
+        try {
+            var res = SQL.db.exec(`SELECT COUNT(*) FROM files WHERE id = ${id}`);
+            return !_.isEmpty(res) && res[0].values[0] > 0;
+        } catch (e) {
+            console.log(e);
+            throw e;
+        }
+    }
+
+    save(item) {
+        const that = this;
+        let saveOne = function (item) {
+            var res;
+            if (!that.exists(item.id))
+                res = SQL.db.run("INSERT INTO files VALUES (NULL, ?, ?, ?, ?)", [item.otherId, item.name, item.magnet, item.date]);
+            else
+                res = SQL.db.run("UPDATE files SET otherId = ?, name = ?, magnet = ?, date = ? WHERE files.id = ?", [item.otherId, item.name, item.magnet, item.date, item.id]);
+
+        };
+        try {
+            if (_.isArray(item)) {
+                Array.from(item).forEach(i => saveOne(i))
+            } else {
+                saveOne(item)
+            }
+
+            this.commit()
+        } catch (e) {
+            console.log(e);
+            throw e;
+        }
+    }
+
+    commit() {
+        SQL.commit();
+    }
+}
+
+module.exports.FileRepo = new FileRepo();

+ 9 - 1
db.js → src/db.js

@@ -4,7 +4,7 @@ let settings = require('./settings.js');
 let SQL = require('sql.js');
 
 function firstRun(db) {
-    db.run("CREATE TABLE files (id INTEGER PRIMARY KEY AUTOINCREMENT, otherId INTEGER, name VARCHAR(256), magnet VARCHAR(256));");
+    db.run("CREATE TABLE files (id INTEGER PRIMARY KEY AUTOINCREMENT, otherId INTEGER, name VARCHAR(256), magnet VARCHAR(256), date INTEGER);");
 }
 
 function initDb() {
@@ -12,6 +12,11 @@ function initDb() {
     if (!fs.existsSync(filepath)) {
         let db = new SQL.Database();
         firstRun(db);
+        try {
+            fs.mkdirSync(settings().userPath);
+            fs.closeSync(fs.openSync(filepath, 'w'));
+        } catch (e) {
+        }
         fs.writeFileSync(filepath, new Buffer(db.export()));
     }
 }
@@ -23,7 +28,10 @@ function loadDb() {
 
 function saveDb(db) {
     let filepath = path.join(settings().userPath, settings().userDbFile);
+    let hrstart = process.hrtime();
     fs.writeFileSync(filepath, new Buffer(db.export()));
+    let hrend = process.hrtime(hrstart);
+    console.info("db commit %dms", (hrend[1] / 1000000).toFixed(2));
 }
 
 initDb();

+ 0 - 0
favicon.ico → src/favicon.ico


+ 2 - 2
frontend.js → src/frontend.js

@@ -2,5 +2,5 @@ const _ = global._ = require('underscore');
 
 require('angular').module('Ks', [require('angular-ui-router'), require('angular-messages'), require('angular-sanitize'), require('angular-material')]);
 require('./route.js');
-require('./modules/root.js');
-require('./modules/nav/knav.js');
+require('./root.js');
+require('./nav/knav.js');

+ 2 - 2
global.css → src/global.css

@@ -1,5 +1,5 @@
-@import "node_modules/angular-material/angular-material.css";
-@import "thirdparty/iconfont/material-icons.css";
+@import "../node_modules/angular-material/angular-material.css";
+@import "../thirdparty/iconfont/material-icons.css";
 
 html, body {
     width: 100%;

+ 1 - 1
index.html → src/index.html

@@ -6,7 +6,7 @@
     <link rel="stylesheet" href="global.css"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
 </head>
-<body ui-view>
+<body ui-view ng-cloak>
 <script>
     require('./frontend.js')
 </script>

+ 13 - 0
src/nav/kfab.html

@@ -0,0 +1,13 @@
+<md-fab-toolbar md-open="fab.open" md-direction="left" class="md-fab-bottom-right">
+    <md-fab-trigger class="align-with-text">
+        <md-button aria-label="menu" class="md-fab md-primary">
+            <md-icon>star</md-icon>
+        </md-button>
+    </md-fab-trigger>
+
+    <md-toolbar layout="row" layout-align="center center">
+        <md-fab-actions class="md-toolbar-tools">
+            <md-button class="md-raised">НАЧАЛО</md-button>
+        </md-fab-actions>
+    </md-toolbar>
+</md-fab-toolbar>

+ 5 - 2
modules/nav/knav.html → src/nav/knav.html

@@ -1,6 +1,9 @@
-<md-toolbar md-scroll-shrink>
+<md-toolbar>
     <div class="md-toolbar-tools">
-        <h2 flex>СПИСОК</h2>
+        <md-button class="md-icon-button" ng-disabled="true">
+            <md-icon>menu</md-icon>
+        </md-button>
+        <h2 flex>RUTOR</h2>
         <md-button class="md-icon-button" ng-click="ipc.send('open:devtools')">
             <md-icon>settings</md-icon>
         </md-button>

+ 11 - 1
modules/nav/knav.js → src/nav/knav.js

@@ -1,7 +1,7 @@
 const path = require('path');
 const ipc = require('electron').ipcRenderer;
 
-require('angular').module('Ks').directive('knav', function () {
+require('angular').module('Ks').directive('toolbar', function () {
     return {
         restrict: 'E',
         replace: true,
@@ -14,4 +14,14 @@ require('angular').module('Ks').directive('knav', function () {
             }
         }
     }
+}).directive('fabbar', function () {
+    return {
+        restrict: 'E',
+        templateUrl: path.join(__dirname, 'kfab.html'),
+        controller: function ($scope, $state) {
+            $scope.fab = {
+                open: false
+            };
+        }
+    }
 });

+ 29 - 0
src/root.html

@@ -0,0 +1,29 @@
+<div layout="column" class="main">
+    <toolbar></toolbar>
+    <div layout="column" layout-align="start">
+        <div layout="row" flex="none">
+            <md-tabs md-selected="data.tab" flex md-dynamic-height md-border-bottom>
+                <md-tab>
+                    <md-tab-label>
+                        <md-icon>local_movies</md-icon>
+                        ФИЛЬМЫ
+                    </md-tab-label>
+                </md-tab>
+                <md-tab>
+                    <md-tab-label>
+                        <md-icon>movie</md-icon>
+                        СЕРИАЛЫ
+                    </md-tab-label>
+                </md-tab>
+            </md-tabs>
+        </div>
+        <md-content flex>
+            <md-list>
+                <md-list-item ng-repeat="i in items">
+                    <div class="md-list-item-content" md-truncate>{{i.name}}</div>
+                </md-list-item>
+            </md-list>
+        </md-content>
+    </div>
+    <fabbar></fabbar>
+</div>

+ 21 - 0
src/root.js

@@ -0,0 +1,21 @@
+let ipc = require('electron').ipcRenderer;
+let S = require('underscore.string');
+let _ = require('underscore');
+require('../thirdparty/naturalSort');
+
+require('angular').module('Ks').controller('RootController', function ($scope) {
+
+    $scope.data = {
+        tab: 0,
+    };
+
+    $scope.items = [];
+
+    ipc.send('get:files');
+
+    ipc.on('ok:files', (e, data) => {
+        $scope.items = _.sortByNat(data, function (f) {
+            return f.name.toLowerCase()
+        })
+    })
+});

+ 1 - 1
route.js → src/route.js

@@ -5,7 +5,7 @@ require('angular').module('Ks').config(function ($stateProvider) {
         name: 'root',
         url: '/',
         controller: 'RootController',
-        templateUrl: path.join(__dirname, 'modules/root.html')
+        templateUrl: path.join(__dirname, 'root.html')
     }).state({
         name: 'otherwise',
         url: '*path',

+ 1 - 1
settings.js → src/settings.js

@@ -5,7 +5,7 @@ let fs = require('fs');
 let _ = require('underscore');
 
 let settings = {
-    appName: require('./package').name,
+    appName: require('../package.json').name,
     userPath: app.getPath('userData'),
     userConfigFile: 'config.json',
     userDbFile: 'data.sqlite',

+ 0 - 0
ui.js → src/ui.js


+ 69 - 0
thirdparty/naturalSort.js

@@ -0,0 +1,69 @@
+let _ = require('underscore');
+
+_.mixin({
+
+    sortByNat: function (obj, value, context) {
+        var iterator = _.isFunction(value) ? value : function (obj) {
+            return obj[value];
+        };
+        return _.pluck(_.map(obj, function (value, index, list) {
+            return {
+                value: value,
+                index: index,
+                criteria: iterator.call(context, value, index, list)
+            };
+        }).sort(function (left, right) {
+            var a = left.criteria;
+            var b = right.criteria;
+            return naturalSort(a, b);
+        }), 'value');
+    }
+});
+
+function naturalSort(a, b) {
+    var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,
+        sre = /(^[ ]*|[ ]*$)/g,
+        dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
+        hre = /^0x[0-9a-f]+$/i,
+        ore = /^0/,
+        i = function (s) {
+            return naturalSort.insensitive && ('' + s).toLowerCase() || '' + s
+        },
+        // convert all to strings strip whitespace
+        x = i(a).replace(sre, '') || '',
+        y = i(b).replace(sre, '') || '',
+        // chunk/tokenize
+        xN = x.replace(re, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0'),
+        yN = y.replace(re, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0'),
+        // numeric, hex or date detection
+        xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)),
+        yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null,
+        oFxNcL, oFyNcL;
+    // first try and sort Hex codes or Dates
+    if (yD)
+        if (xD < yD) return -1;
+        else if (xD > yD) return 1;
+    // natural sorting through split numeric strings and default strings
+    for (var cLoc = 0, numS = Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
+        // find floats not starting with '0', string or 0 if not defined (Clint Priest)
+        oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
+        oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
+        // handle numeric vs string comparison - number < string - (Kyle Adams)
+        if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
+            return (isNaN(oFxNcL)) ? 1 : -1;
+        }
+        // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
+        else if (typeof oFxNcL !== typeof oFyNcL) {
+            oFxNcL += '';
+            oFyNcL += '';
+        }
+        if (oFxNcL < oFyNcL) return -1;
+        if (oFxNcL > oFyNcL) return 1;
+    }
+    return 0;
+}
+
+// extend Array to have a natural sort
+Array.prototype.sortNat = function () {
+    return Array.prototype.sort.call(this, naturalSort)
+};