museria 0.2.39 → 0.2.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * museria face
3
- * @version 0.2.39
3
+ * @version 0.2.43
4
4
  * {@link https://github.com/ortexx/museria}
5
5
  */
6
6
  /*!
@@ -17,4 +17,4 @@
17
17
  */@font-face{font-display:block;font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(fa-solid-900.eot);src:url(fa-solid-900.eot) format("embedded-opentype"),url(fa-solid-900.woff2) format("woff2"),url(fa-solid-900.woff) format("woff"),url(fa-solid-900.ttf) format("truetype"),url(fa-solid-900.svg) format("svg")}.fa,.fas{font-family:Font Awesome\ 5 Free;font-weight:900}/*!
18
18
  * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
19
19
  * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
20
- */@font-face{font-display:block;font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(fa-brands-400.eot);src:url(fa-brands-400.eot) format("embedded-opentype"),url(fa-brands-400.woff2) format("woff2"),url(fa-brands-400.woff) format("woff"),url(fa-brands-400.ttf) format("truetype"),url(fa-brands-400.svg) format("svg")}.fab{font-family:Font Awesome\ 5 Brands;font-weight:400}@font-face{font-family:ProximaNova;src:url(proxima-nova.ttf)}@font-face{font-family:OpenSans;src:url(open-sans.ttf)}*{margin:0;padding:0}body{background:#353535;color:#ccc;font-family:OpenSans;height:100%;overflow-y:scroll}.custom-file input{cursor:pointer;text-indent:-1000px}.custom-control-label{cursor:pointer;opacity:.8}.custom-control-label:hover{opacity:1}.btn{font-weight:700;padding:0;text-transform:uppercase}.btn:active,.btn:focus{box-shadow:none!important;outline:none!important}.btn[disabled]{cursor:not-allowed}a{color:#ccc;text-decoration:underline}a:hover{color:#ccc;text-decoration:none}.input-group-lg input[type=text]{height:auto;padding:.42rem 1rem .45rem}.alert-success{background-color:#25301f;border-color:#28a745;color:#aed3b7}.alert-danger{background-color:#301f1f;border-color:#c00;color:#d3aeae}.alert-info{background-color:#1f2730;border-color:#0af;color:#aec7d3}.invalid-feedback{color:#f39595}.close-fa{color:#666;cursor:pointer;opacity:.7;position:absolute;right:.9em;top:50%;transform:translateY(-50%);z-index:2}.close-fa:hover{opacity:1}.app{display:flex;flex-direction:column;height:100vh}.app .wmodal-overlay{align-items:center;background:rgba(34,34,34,.8);cursor:pointer;display:flex;height:100vh;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:11000}.app .wmodal-close{color:#666;cursor:pointer;font-size:1.8em;opacity:.4;position:absolute;right:.55em;top:.5em}.app .wmodal-close:hover{opacity:1}.app .wmodal-body{background:#000;box-shadow:0 0 4px 2px hsla(0,0%,40%,.6);box-sizing:border-box;cursor:default;padding:3.5em 2.5em;position:relative}.app .upload-events .wmodal-close{font-size:2em;right:1em;top:50%;transform:translateY(-50%)}.app .upload-events .wmodal-body{padding:2em 5em 2em 2em;word-break:break-all}.app .upload-events .wmodal-body.danger{box-shadow:0 0 4px 2px rgba(204,0,0,.6)}.app .upload-events .wmodal-body.success{box-shadow:0 0 4px 2px rgba(40,167,69,.6)}.app .finding-list>*{display:block}.app .finding-list>:not(:first-child){margin-top:.5em}.app .captcha input{background:#151515;border-color:#292929;width:240px}.app .captcha input:focus{background:#151515;border-color:#666}.app .captcha-preloader{color:#666;font-size:1.7em;text-align:center}.app .header{background:#333;background:radial-gradient(#666,#464646,#333);padding:8.2em 0 6.6em;text-shadow:0 0 .8em #333}.app .header .logo{display:flex;font-family:ProximaNova;font-weight:700;text-decoration:none;text-transform:uppercase}.app .header .logo-img{display:inline-block;vertical-align:middle;width:3em}.app .header .logo-title{color:#fff;display:inline-block;font-size:3em;letter-spacing:.05em;margin-left:.1em;vertical-align:middle}.app .header .logo-description-start{color:#d7cf9b;font-size:2em;letter-spacing:.07em;margin-left:.1em;margin-top:-.3em}.app .header .logo-description-end{color:#d7cf9b;font-size:7.2em;letter-spacing:.03em;margin-left:.2em;margin-top:-.21em}.app .header .logo-description-end-lg{color:#d7cf9b;font-size:3.6em;letter-spacing:.06em;margin-top:-.2em}.app .content{flex:1}.app .footer{background:#333;background:radial-gradient(#555,#424242,#333);color:#ccc;padding:1.5em 0 3em}.app .footer h5{color:#d7cf9b;font-weight:700;margin-bottom:.6em;opacity:.7;text-shadow:0 0 1em #000;text-transform:uppercase}.app .footer a{color:#ccc;text-decoration:none}.app .footer a:hover{text-decoration:underline}.app .footer ul.nav>li{font-size:.9em;line-height:1.8em;word-break:break-all}.app .song-search .alert.alert-success a{color:#aed3b7;text-decoration:none}.app .song-search .alert.alert-success a:hover{color:#28a745}.app .song-search-input{position:relative}.app .song-search-input>i{color:#888;left:.7em;position:absolute;top:50%;transform:translateY(-50%);z-index:1}.app .song-search-input>i.song-search-loading{margin-top:-.37em}.app .song-search-input>i.song-search-close{cursor:pointer;left:unset;opacity:.6;right:.7em}.app .song-search-input>i.song-search-close:hover{opacity:1}.app .song-search-input>input{padding-left:2.5em}.app .song-search-input>input:focus{z-index:0}.app .cover-img{height:2.22em;left:2px;object-fit:cover;pointer-events:none;position:absolute;top:1px;width:2.22em;z-index:2}.app .cover-remove{right:4.5em}.app .cover-label.with-img{padding-left:3em}.app .upload-preloader-btn i{color:#ccc;font-size:1.4em;margin-left:.3em;margin-top:-.1em;vertical-align:middle}.app .song-priority{font-size:.9em}.app .image-link{align-items:center;color:#fff;display:inline-flex;flex-direction:row;opacity:.7;text-decoration:none}.app .image-link:hover{opacity:1}.app .image-link-pic{font-size:3em}.app .image-link-title{font-size:3em;margin-left:.5em;text-transform:uppercase}.app #audio-file{left:-10000px}.app .questions{display:inline-block;list-style:none;margin:0;text-align:left}.app .questions>li{opacity:.9}.app .questions>li:not(:last-child){margin-bottom:2em}.app .questions>li>:first-child{color:#fff;font-size:1.5em;font-weight:700;text-transform:uppercase}.app .questions>li>:last-child{color:#ccc;font-size:1.4em}.app .questions>li>:last-child:before{color:#86e29b;content:"↵";display:inline-block;font-weight:700;margin:0 .4em 0 0;transform:scaleX(-1)}
20
+ */@font-face{font-display:block;font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(fa-brands-400.eot);src:url(fa-brands-400.eot) format("embedded-opentype"),url(fa-brands-400.woff2) format("woff2"),url(fa-brands-400.woff) format("woff"),url(fa-brands-400.ttf) format("truetype"),url(fa-brands-400.svg) format("svg")}.fab{font-family:Font Awesome\ 5 Brands;font-weight:400}@font-face{font-family:ProximaNova;src:url(proxima-nova.ttf)}@font-face{font-family:OpenSans;src:url(open-sans.ttf)}*{margin:0;padding:0}body{background:#353535;color:#ccc;font-family:OpenSans;height:100%;overflow-y:scroll}.custom-file input{cursor:pointer;text-indent:-1000px}.custom-control-label{cursor:pointer;opacity:.8}.custom-control-label:hover{opacity:1}.btn{font-weight:700;padding:0;text-transform:uppercase}.btn:active,.btn:focus{box-shadow:none!important;outline:none!important}.btn[disabled]{cursor:not-allowed}a{color:#ccc;text-decoration:underline}a:hover{color:#ccc;text-decoration:none}.input-group-lg input[type=text]{height:auto;padding:.42rem 1rem .45rem}.alert-success{background-color:#25301f;border-color:#28a745;color:#aed3b7}.alert-danger{background-color:#301f1f;border-color:#c00;color:#d3aeae}.alert-info{background-color:#1f2730;border-color:#0af;color:#aec7d3}.invalid-feedback{color:#f39595}.close-fa{color:#666;cursor:pointer;opacity:.7;position:absolute;right:.9em;top:50%;transform:translateY(-50%);z-index:2}.close-fa:hover{opacity:1}.app{display:flex;flex-direction:column;height:100vh}.app .wmodal-overlay{align-items:center;background:rgba(34,34,34,.8);cursor:pointer;display:flex;height:100vh;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:11000}.app .wmodal-close{color:#666;cursor:pointer;font-size:1.8em;opacity:.4;position:absolute;right:.55em;top:.5em}.app .wmodal-close:hover{opacity:1}.app .wmodal-body{background:#000;box-shadow:0 0 4px 2px hsla(0,0%,40%,.6);box-sizing:border-box;cursor:default;padding:3.5em 2.5em;position:relative}.app .upload-events .wmodal-close{font-size:2em;right:1em;top:50%;transform:translateY(-50%)}.app .upload-events .wmodal-body{padding:2em 5em 2em 2em;word-break:break-all}.app .upload-events .wmodal-body.danger{box-shadow:0 0 4px 2px rgba(204,0,0,.6)}.app .upload-events .wmodal-body.success{box-shadow:0 0 4px 2px rgba(40,167,69,.6)}.app .finding-list>*{display:block}.app .finding-list>:not(:first-child){margin-top:.5em}.app .captcha input{background:#151515;border-color:#292929;width:240px}.app .captcha input:focus{background:#151515;border-color:#666}.app .captcha-preloader{color:#666;font-size:1.7em;text-align:center}.app .header{background:#333;background:radial-gradient(#666,#464646,#333);padding:8.2em 0 6.6em;position:relative;text-shadow:0 0 .8em #333}.app .header .songs-counter-text{bottom:1.5em;color:#666;font-weight:700;left:50%;position:absolute;text-align:center;text-transform:uppercase;transform:translateX(-50%)}.app .header .songs-counter-text b{color:#888}.app .header .logo{display:flex;font-family:ProximaNova;font-weight:700;text-decoration:none;text-transform:uppercase}.app .header .logo-img{display:inline-block;vertical-align:middle;width:3em}.app .header .logo-title{color:#fff;display:inline-block;font-size:3em;letter-spacing:.05em;margin-left:.1em;vertical-align:middle}.app .header .logo-description-start{color:#d7cf9b;font-size:2em;letter-spacing:.07em;margin-left:.1em;margin-top:-.3em}.app .header .logo-description-end{color:#d7cf9b;font-size:7.2em;letter-spacing:.03em;margin-left:.2em;margin-top:-.21em}.app .header .logo-description-end-lg{color:#d7cf9b;font-size:3.6em;letter-spacing:.06em;margin-top:-.2em}.app .content{flex:1}.app .footer{background:#333;background:radial-gradient(#555,#424242,#333);color:#ccc;padding:1.5em 0 3em}.app .footer h5{color:#d7cf9b;font-weight:700;margin-bottom:.6em;opacity:.7;text-shadow:0 0 1em #000;text-transform:uppercase}.app .footer a{color:#ccc;text-decoration:none}.app .footer a:hover{text-decoration:underline}.app .footer ul.nav>li{font-size:.9em;line-height:1.8em;word-break:break-all}.app .song-search .alert.alert-success a{color:#aed3b7;text-decoration:none}.app .song-search .alert.alert-success a:hover{color:#28a745}.app .song-search-input{position:relative}.app .song-search-input>i{color:#888;left:.7em;position:absolute;top:50%;transform:translateY(-50%);z-index:1}.app .song-search-input>i.song-search-loading{margin-top:-.37em}.app .song-search-input>i.song-search-close{cursor:pointer;left:unset;opacity:.6;right:.7em}.app .song-search-input>i.song-search-close:hover{opacity:1}.app .song-search-input>input{padding-left:2.5em;padding-right:2em}.app .song-search-input>input:focus{z-index:0}.app .cover-img{height:2.22em;left:2px;object-fit:cover;pointer-events:none;position:absolute;top:1px;width:2.22em;z-index:2}.app .cover-remove{right:4.5em}.app .cover-label.with-img{padding-left:3em}.app .upload-preloader-btn i{color:#ccc;font-size:1.4em;margin-left:.3em;margin-top:-.1em;vertical-align:middle}.app .song-priority{font-size:.9em}.app .image-link{align-items:center;color:#fff;display:inline-flex;flex-direction:row;opacity:.7;text-decoration:none}.app .image-link:hover{opacity:1}.app .image-link-pic{font-size:3em}.app .image-link-title{font-size:3em;margin-left:.5em;text-transform:uppercase}.app #audio-file{left:-10000px}.app .questions{display:inline-block;list-style:none;margin:0;text-align:left}.app .questions>li{opacity:.9}.app .questions>li:not(:last-child){margin-bottom:2em}.app .questions>li>:first-child{color:#fff;font-size:1.5em;font-weight:700;text-transform:uppercase}.app .questions>li>:last-child{color:#ccc;font-size:1.4em}.app .questions>li>:last-child:before{color:#86e29b;content:"↵";display:inline-block;font-weight:700;margin:0 .4em 0 0;transform:scaleX(-1)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "museria",
3
- "version": "0.2.39",
3
+ "version": "0.2.43",
4
4
  "description": "Decentralized music storage",
5
5
  "main": "./src/index.js",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  "homepage": "https://github.com/ortexx/museria",
14
14
  "scripts": {
15
15
  "eslint": "eslint src bin test",
16
- "test": "mocha ./test/index.js --timeout=20000",
16
+ "test": "mocha ./test/index.js --timeout=30000",
17
17
  "build-client": "webpack --config=webpack.client.js",
18
18
  "build-client-prod": "cross-env NODE_ENV=production webpack --config=webpack.client.js",
19
19
  "build-face": "webpack --config=webpack.face.js",
@@ -77,7 +77,7 @@
77
77
  "express": "^4.17.1",
78
78
  "fs-extra": "^9.0.1",
79
79
  "lodash": "^4.17.20",
80
- "metastocle": "^0.2.25",
80
+ "metastocle": "^0.2.27",
81
81
  "music-metadata": "^6.4.0",
82
82
  "node-fetch": "^2.6.1",
83
83
  "node-id3": "^0.2.2",
@@ -85,8 +85,8 @@
85
85
  "serve-favicon": "^2.5.0",
86
86
  "sharp": "^0.25.2",
87
87
  "splaytree": "^3.1.0",
88
- "spreadable": "^0.2.21",
89
- "storacle": "^0.2.21",
88
+ "spreadable": "^0.2.23",
89
+ "storacle": "^0.2.23",
90
90
  "transliteration": "^2.2.0"
91
91
  },
92
92
  "repository": {
@@ -1,4 +1,4 @@
1
- <div class="app container-fluid">
1
+ <div class="app container-fluid">
2
2
  <if recreate is="${ this.showCaptcha }" class="captcha wmodal">
3
3
  <div
4
4
  class="wmodal-overlay"
@@ -48,6 +48,9 @@
48
48
  </div>
49
49
  </if>
50
50
  <header class="header row">
51
+ <div class="songs-counter-text">
52
+ There ${this.songsCount == 1? 'is': 'are'} <b>${ Number(this.songsCount).toLocaleString() }</b> song${this.songsCount == 1? '': 's'} on the network
53
+ </div>
51
54
  <a state="app" class="logo mx-auto px-4">
52
55
  <div>
53
56
  <img src="./img/logo.svg" class="logo-img">
@@ -55,12 +58,12 @@
55
58
  <div class="logo-description-start">decentralized</div>
56
59
  <div class="logo-description-end-lg d-lg-none">storage</div>
57
60
  </div>
58
- <div class="logo-description-end d-none d-lg-block">storage</div>
61
+ <div class="logo-description-end d-none d-lg-block">storage</div>
59
62
  </a>
60
63
  </header>
61
- <div class="content">
64
+ <div class="content">
62
65
  <div class="row pt-5 pb-3">
63
- <div class="song-search col-lg-6 col-12 pl-5 pr-5 pr-lg-4 pt-4">
66
+ <div class="song-search col-lg-6 col-12 pl-5 pr-5 pr-lg-4 pt-4">
64
67
  <div class="song-search-input input-group input-group-lg">
65
68
  <i hidden="${ this.isFinding }" class="fas fa-search fa-lg"></i>
66
69
  <i hidden="${ !this.isFinding }" class="fas fa-circle-notch fa-spin song-search-loading fa-lg"></i>
@@ -240,10 +243,9 @@
240
243
  </div>
241
244
  </li>
242
245
  <li>
243
- <div>How many songs are in this node?</div>
246
+ <div>Where can I get the node status?</div>
244
247
  <div>
245
- There are <b class="text-warning">${ this.songsCount }</b> song(s) at the moment. You also can find more info about the node status
246
- <a href="/status?pretty" target="_blank">here</a>.
248
+ There is a special route <a href="/status?pretty" target="_blank">here</a>.
247
249
  </div>
248
250
  </li>
249
251
  <li>
@@ -1,7 +1,6 @@
1
1
  import './app.scss';
2
2
  import Akili from 'akili';
3
3
  import router from 'akili/src/services/router';
4
- import request from 'akili/src/services/request';
5
4
  import client from '../../client';
6
5
 
7
6
  export default class App extends Akili.Component {
@@ -19,7 +18,7 @@ export default class App extends Akili.Component {
19
18
  created() {
20
19
  this.captchaWidth = 240;
21
20
  this.findingSongsLimit = 10;
22
- this.songsCountInterval = 10 * 1000;
21
+ this.songsCountInterval = 15 * 1000;
23
22
  this.songsCountIntervalObj = null;
24
23
  this.scope.songsCount = 0;
25
24
  this.scope.searchInputValue = this.transition.query.f;
@@ -83,8 +82,7 @@ export default class App extends Akili.Component {
83
82
  }
84
83
 
85
84
  async setSongsCount() {
86
- const data = (await request.get('/status', { json: true })).data;
87
- this.scope.songsCount = data.filesCount;
85
+ this.scope.songsCount = await client.getNetworkFilesCount();
88
86
  }
89
87
 
90
88
  setFindingValue(val) {
@@ -3,7 +3,7 @@
3
3
  .app {
4
4
  display: flex;
5
5
  height: 100vh;
6
- flex-direction: column;
6
+ flex-direction: column;
7
7
 
8
8
  .wmodal {
9
9
  &-overlay {
@@ -96,11 +96,27 @@
96
96
  }
97
97
 
98
98
  & .header {
99
+ position: relative;
99
100
  background: #333;
100
101
  background: radial-gradient(#666,#464646, #333);
101
102
  padding: 8.2em 0 6.6em 0;
102
103
  text-shadow: 0px 0px 0.8em #333;
103
104
 
105
+ & .songs-counter-text {
106
+ position: absolute;
107
+ left: 50%;
108
+ transform: translateX(-50%);
109
+ bottom: 1.5em;
110
+ color: $gray;
111
+ text-transform: uppercase;
112
+ font-weight: bold;
113
+ text-align: center;
114
+
115
+ & b {
116
+ color: $light;
117
+ }
118
+ }
119
+
104
120
  & .logo {
105
121
  display: flex;
106
122
  font-family: ProximaNova;
@@ -197,7 +213,7 @@
197
213
  }
198
214
 
199
215
  &-input {
200
- position: relative;
216
+ position: relative;
201
217
 
202
218
  & > i {
203
219
  position: absolute;
@@ -224,8 +240,9 @@
224
240
  }
225
241
 
226
242
  & > input {
227
- padding-left: 2.5em;
228
-
243
+ padding-left: 2.5em;
244
+ padding-right: 2em;
245
+
229
246
  &:focus {
230
247
  z-index: 0;
231
248
  }
package/src/client.js CHANGED
@@ -24,7 +24,7 @@ module.exports = (Parent) => {
24
24
  }
25
25
  }, options);
26
26
  super(options);
27
- }
27
+ }
28
28
 
29
29
  /**
30
30
  * Get the song complete info
package/src/node.js CHANGED
@@ -78,8 +78,7 @@ module.exports = (Parent) => {
78
78
  ]
79
79
  },
80
80
  task: {
81
- cleanUpMusicInterval: '1m',
82
- normalizeSongTitlesInterval: '10m',
81
+ cleanUpMusicInterval: '1m'
83
82
  }
84
83
  }, options);
85
84
 
@@ -120,10 +119,6 @@ module.exports = (Parent) => {
120
119
  if(this.options.task.cleanUpMusicInterval) {
121
120
  await this.task.add('cleanUpMusic', this.options.task.cleanUpMusicInterval, () => this.cleanUpMusic());
122
121
  }
123
-
124
- if(this.options.task.normalizeSongTitlesInterval) {
125
- await this.task.add('normalizeSongTitles', this.options.task.normalizeSongTitlesInterval, () => this.normalizeSongTitles());
126
- }
127
122
  }
128
123
 
129
124
  /**
@@ -133,9 +128,19 @@ module.exports = (Parent) => {
133
128
  */
134
129
  async normalizeSongTitles() {
135
130
  const docs = await this.db.getDocuments('music');
131
+ const titles = {};
132
+
136
133
  for(let i = 0; i < docs.length; i++) {
137
134
  const doc = docs[i];
138
- doc.title = utils.beautifySongTitle(doc.title);
135
+ const title = utils.beautifySongTitle(doc.title);
136
+
137
+ if(titles[title] && titles[title] != doc.$loki) {
138
+ await this.db.deleteDocument(doc);
139
+ continue;
140
+ }
141
+
142
+ doc.title = title;
143
+ titles[title] = doc.$loki;
139
144
  await this.db.updateMusicDocument(doc, { beautify: false });
140
145
  }
141
146
  }
@@ -421,8 +426,7 @@ module.exports = (Parent) => {
421
426
  * @returns {object[]}
422
427
  */
423
428
  async getSongInfo(title, options = {}) {
424
- title = utils.beautifySongTitle(title);
425
- this.songTitleTest(title);
429
+ title = utils.prepareComparisonSongTitle(title);
426
430
  const collection = await this.getCollection('music');
427
431
  const actions = utils.prepareDocumentGettingActions({
428
432
  offset: 0,
@@ -467,7 +471,7 @@ module.exports = (Parent) => {
467
471
  * @returns {object[]}
468
472
  */
469
473
  async findSongs(str, options = {}) {
470
- const title = utils.beautifySongTitle(str);
474
+ const title = utils.prepareComparisonSongTitle(str);
471
475
  str = utils.prepareSongFindingString(str);
472
476
 
473
477
  if(str.length < this.options.music.findingStringMinLength) {
@@ -8,7 +8,7 @@ module.exports.requestSong = node => {
8
8
  return async (req, res, next) => {
9
9
  try {
10
10
  const title = req.query.title;
11
- node.songTitleTest(title);
11
+ node.songTitleTest(title);
12
12
  const link = await node.getSongLink(title, req.query.type);
13
13
 
14
14
  if(!link) {
@@ -131,4 +131,4 @@ module.exports.removeSong = node => {
131
131
  next(err);
132
132
  }
133
133
  }
134
- };
134
+ };
@@ -121,5 +121,5 @@ module.exports = [
121
121
  midds.requestQueueClient,
122
122
  controllers.removeSong
123
123
  ]
124
- }
124
+ }
125
125
  ];
@@ -1,4 +1,5 @@
1
- const ServerExpressMetastocle = require('metastocle/src/server/transports/express')();
1
+ const ServerExpressStoracle = require('storacle/src/server/transports/express')();
2
+ const ServerExpressMetastocle = require('metastocle/src/server/transports/express')(ServerExpressStoracle);
2
3
  const routes = require('./routes');
3
4
  const routesClient = require('./client/routes');
4
5
  const routesApi = require('./api/routes');
@@ -29,7 +30,7 @@ module.exports = (Parent) => {
29
30
  const remove = [
30
31
  'addDocument', 'updateDocuments',
31
32
  'deleteDocuments', 'getDocumentsCount',
32
- 'getDocumentByPk', 'getDocuments'
33
+ 'getDocumentByPk', 'getDocuments', 'removeFile'
33
34
  ];
34
35
  return super.getClientRoutes().filter(r => !remove.includes(r.name)).concat(routesClient);
35
36
  }
@@ -45,7 +46,7 @@ module.exports = (Parent) => {
45
46
  * @see ServerExpressMetastocle.prototype.getApiMasterRoutes
46
47
  */
47
48
  getApiMasterRoutes() {
48
- const remove = ['updateDocuments', 'deleteDocuments'];
49
+ const remove = ['updateDocuments', 'deleteDocuments', 'removeFile'];
49
50
  return super.getApiMasterRoutes().filter(r => !remove.includes(r.name)).concat(routesApiMaster);
50
51
  }
51
52
 
@@ -53,7 +54,7 @@ module.exports = (Parent) => {
53
54
  * @see ServerExpressMetastocle.prototype.getApiButlerRoutes
54
55
  */
55
56
  getApiButlerRoutes() {
56
- const remove = ['updateDocuments', 'deleteDocuments'];
57
+ const remove = ['updateDocuments', 'deleteDocuments', 'removeFile'];
57
58
  return super.getApiButlerRoutes().filter(r => !remove.includes(r.name)).concat(routesApiButler);
58
59
  }
59
60
 
@@ -61,7 +62,7 @@ module.exports = (Parent) => {
61
62
  * @see ServerExpressMetastocle.prototype.getApiSlaveRoutes
62
63
  */
63
64
  getApiSlaveRoutes() {
64
- const remove = ['updateDocuments', 'deleteDocuments'];
65
+ const remove = ['updateDocuments', 'deleteDocuments', 'removeFile'];
65
66
  return super.getApiSlaveRoutes().filter(r => !remove.includes(r.name)).concat(routesApiSlave);
66
67
  }
67
68
 
@@ -69,7 +70,7 @@ module.exports = (Parent) => {
69
70
  * @see ServerExpressMetastocle.prototype.getApiNodeRoutes
70
71
  */
71
72
  getApiNodeRoutes() {
72
- const remove = ['addDocument'];
73
+ const remove = ['addDocument', 'storFile'];
73
74
  return super.getApiNodeRoutes().filter(r => !remove.includes(r.name)).concat(routesApiNode);
74
75
  }
75
76
  }
@@ -66,7 +66,7 @@ midds.fileAccess = node => {
66
66
 
67
67
  if(!doc) {
68
68
  const titleHash = String(req.params.hash).split('.')[0];
69
- const title = utils.decodeSongTitle(titleHash);
69
+ const title = utils.decodeSongTitle(titleHash);
70
70
  doc = await node.db.getMusicByPk(title);
71
71
  }
72
72
 
package/src/utils.js CHANGED
@@ -9,7 +9,7 @@ const mm = require('music-metadata');
9
9
  const base64url = require('base64url');
10
10
 
11
11
  utils.regexSongLinks = /(([a-z]+:\/\/)?[-\p{L}\p{N}]+\.[\p{L}]{2,}|[a-z]+:\/\/(\[:*[\w\d]+:[\w\d:]+\]|\d+\.[\d.]+))\S*/igu;
12
- utils.regexSongFeats = /[([\s]+((ft\.?|feat\.?|featuring)[\s]+((?!(\s+[-([)\]]+))[^)\]])+)\s*[)\]]*([\s]+[-([]+|$)/i;
12
+ utils.regexSongFeats = /[([\s]+((ft\.|feat\.)[\s]+((?!(\s+[-([)\]]+))[^)\]])+)\s*[)\]]*([\s]+[-([]+|$)/iu;
13
13
 
14
14
  utils.heritableSongTags = [
15
15
  'TALB', 'TCOM', 'TCON', 'TCOP', 'TDAT', 'TEXT', 'TIT1', 'TIT3', 'TLAN',
@@ -37,7 +37,7 @@ utils.MusicDocumentsHandler = class extends utils.DocumentsHandler {
37
37
 
38
38
  return this.$ilk(value, filter);
39
39
  }
40
- }
40
+ }
41
41
 
42
42
  /**
43
43
  * @see stUtils.getFileInfo
@@ -125,11 +125,20 @@ utils.beautifySongTitle = function (title) {
125
125
  .replace(/[\sᅠ]+/g, ' ')
126
126
  .replace(/([([])\s+/g, '$1')
127
127
  .replace(/\s+([)\]])/g, '$1')
128
+ .replace(/([([]+)(featuring|feat|ft)(\s)/ig, '$1feat.$3')
129
+ .replace(/([([\s]+)(feat\.|ft\.)(\s)/ig, '$1feat.$3')
128
130
  .toLowerCase();
129
131
 
130
132
  if(!/[^\s]+ - [^\s]+/.test(title)) {
131
133
  return '';
132
134
  }
135
+
136
+ const arr = title.split(/\(?feat\./i);
137
+
138
+ if(arr.length > 2) {
139
+ arr.splice(2, arr.length - 2);
140
+ title = arr.join('(feat.').trim();
141
+ }
133
142
 
134
143
  const sides = this.splitSongTitle(title);
135
144
  let artists = sides[0].split(/,[\s]*/);
@@ -139,26 +148,26 @@ utils.beautifySongTitle = function (title) {
139
148
  if(!mainArtist) {
140
149
  return '';
141
150
  }
142
-
143
- const match = title.match(this.regexSongFeats);
151
+
152
+ const match = sides[1].match(this.regexSongFeats);
144
153
  let feats = (match? match[1]: '').replace(/,([^\s])/, ', $1').trim();
145
154
  title = `${mainArtist} - ${sides[1]}`;
146
- title = title.replace(this.regexSongFeats, '$5');
147
- artists = artists.map(a => a.trim());
148
-
155
+ title = title.replace(this.regexSongFeats, '$5');
156
+ feats && (artists = artists.concat(feats.replace(/feat\./i, '').split(',')));
157
+ artists = [...new Set(artists.map(a => a.trim()).filter(v => v))];
158
+
149
159
  if(artists.length) {
150
- feats = feats? [feats].concat(artists).join(', '): `ft. ${ artists.join(', ') }`;
160
+ feats = `feat. ${ artists.join(', ') }`;
151
161
  }
152
162
 
153
163
  feats && (title += ` (${feats})`);
154
- title = title
155
- .replace(/([([\s]+)(feat\.?|ft\.?|featuring)(\s)/i, '$1feat.$3')
164
+ title = title
156
165
  .replace(/\[\]|\(\)/g, '')
157
166
  .replace(/\s+/g, ' ')
158
167
  .split(' ')
159
168
  .map(p => p? (p[0].toUpperCase() + p.slice(1)): p)
160
169
  .join(' ')
161
- .trim()
170
+ .trim();
162
171
  return title;
163
172
  };
164
173
 
@@ -234,8 +243,8 @@ utils.getSongArtists = function (title, options = {}) {
234
243
  const sides = this.splitSongTitle(title);
235
244
  let artists = sides[0].split(/,/);
236
245
  const match = title.match(this.regexSongFeats);
237
- let feats = (match? match[1]: '').replace(/(feat|ft|featuring)\.?/i, '');
238
- return artists.concat(feats.split(',')).map(v => v.trim()).filter(v => v);
246
+ let feats = (match? match[1]: '').replace(/^feat\./i, '');
247
+ return [...new Set(artists.concat(feats.split(',')).map(v => v.trim()).filter(v => v))];
239
248
  };
240
249
 
241
250
  /**
package/test/client.js CHANGED
@@ -336,7 +336,7 @@ describe('Client', () => {
336
336
  assert.isNull(await node.db.getMusicByPk(title), 'check the database');
337
337
  assert.isFalse(await node.hasFile(doc.fileHash), 'check the file');
338
338
  });
339
- });
339
+ });
340
340
 
341
341
  describe('.createRequestedSongAudioLink()', () => {
342
342
  it('should return the right link', async () => {
package/test/group.js CHANGED
@@ -164,5 +164,5 @@ describe('group communication', () => {
164
164
 
165
165
  assert.isOk(fCount >= length * duplicates, 'check the files');
166
166
  assert.isOk(dCount >= length * duplicates, 'check the documents');
167
- });
167
+ });
168
168
  });
package/test/node.js CHANGED
@@ -108,17 +108,13 @@ describe('Node', () => {
108
108
  });
109
109
 
110
110
  describe('.getSongInfo()', () => {
111
- it('should throw an error', async () => {
112
- try {
113
- await node.getSongInfo('unexistent song');
114
- throw new Error('Fail');
115
- }
116
- catch (err) {
117
- assert.isOk(err.message.match('Wrong song title'));
118
- }
111
+ it('should return an empty array with a wrong title', async () => {
112
+ const title = 'unexistent';
113
+ const result = await node.getSongInfo(title);
114
+ assert.lengthOf(result, 0);
119
115
  });
120
116
 
121
- it('should return an empty array', async () => {
117
+ it('should return an empty array with a right title', async () => {
122
118
  const title = 'unexistent - unexistent';
123
119
  const result = await node.getSongInfo(title);
124
120
  assert.lengthOf(result, 0);
package/test/routes.js CHANGED
@@ -361,7 +361,7 @@ describe('routes', () => {
361
361
  assert.isNull(await node.db.getMusicByPk(title), 'check the database');
362
362
  assert.isFalse(await node.hasFile(doc.fileHash), 'check the file');
363
363
  });
364
- });
364
+ });
365
365
 
366
366
  describe('/api/master/remove-song/', function () {
367
367
  it('should return an auth error', async function () {
package/test/utils.js CHANGED
@@ -67,14 +67,13 @@ describe('utils', () => {
67
67
 
68
68
  it('should place feats together', () => {
69
69
  const res = utils.beautifySongTitle('artist1, artist2,artist3 - title (feat. artist4, artist5,artist6)');
70
- assert.equal(res, 'Artist1 - Title (feat. Artist4, Artist5, Artist6, Artist2, Artist3)');
70
+ assert.equal(res, 'Artist1 - Title (feat. Artist2, Artist3, Artist4, Artist5, Artist6)');
71
71
  });
72
72
 
73
73
  it('should bring all feats to a single form', () => {
74
74
  assert.equal(utils.beautifySongTitle('artist - title (ft. Artist)'), 'Artist - Title (feat. Artist)', 'check "ft"');
75
75
  assert.equal(utils.beautifySongTitle('artist - title (feat. Artist)'), 'Artist - Title (feat. Artist)', 'check "feat"');
76
- assert.equal(utils.beautifySongTitle('artist - title (featuring Artist)'), 'Artist - Title (feat. Artist)', 'check "featuring"');
77
- assert.equal(utils.beautifySongTitle('artist - title ft Artist'), 'Artist - Title (feat. Artist)', 'check without brackets');
76
+ assert.equal(utils.beautifySongTitle('artist - title ft. Artist'), 'Artist - Title (feat. Artist)', 'check without brackets');
78
77
  });
79
78
 
80
79
  it('should change the dash type', () => {
@@ -133,8 +132,8 @@ describe('utils', () => {
133
132
  });
134
133
 
135
134
  it('should return the right array', () => {
136
- const artists = utils.getSongArtists('artist,artist2 - title ft. artist3, artist4', { beautify: false });
137
- assert.equal(artists.join(','), 'artist,artist2,artist3,artist4');
135
+ const artists = utils.getSongArtists('artist,artist2 - title ft. artist3, artist4');
136
+ assert.equal(artists.join(','), 'Artist,Artist2,Artist3,Artist4');
138
137
  });
139
138
  });
140
139