« get me outta code hell

mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
path: root/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'index.js')
-rwxr-xr-xindex.js181
1 files changed, 115 insertions, 66 deletions
diff --git a/index.js b/index.js
index 3ecd59b..6aad592 100755
--- a/index.js
+++ b/index.js
@@ -2,42 +2,26 @@
 
 // omg I am tired of code
 
-const { getAllCrawlersForArg } = require('./crawlers')
-const { getPlayer } = require('./players')
-const { parseOptions } = require('./general-util')
-const AppElement = require('./ui')
-const Backend = require('./backend')
-const TelnetServer = require('./telnet')
-const processSmartPlaylist = require('./smart-playlist')
-const setupClient = require('./client')
-
-const {
+import {getPlayer} from './players.js'
+import {parseOptions} from './general-util.js'
+import {getItemPathString} from './playlist-utils.js'
+import Backend from './backend.js'
+import setupClient from './client.js'
+import TelnetServer from './telnet.js'
+
+import {
   makeSocketServer,
   makeSocketClient,
   attachBackendToSocketClient,
-  attachSocketServerToBackend
-} = require('./socket')
-
-const {
-  getItemPathString,
-  updatePlaylistFormat
-} = require('./playlist-utils')
-
-const {
-  ui: {
-    Root
-  },
-  util: {
-    ansi,
-    CommandLineInterfacer,
-    Flushable
-  }
-} = require('tui-lib')
+  attachSocketServerToBackend,
+} from './socket.js'
+
+import {CommandLineInterface} from 'tui-lib/util/interfaces'
+import * as ansi from 'tui-lib/util/ansi'
 
-const { promisify } = require('util')
-const fs = require('fs')
-const readFile = promisify(fs.readFile)
-const writeFile = promisify(fs.writeFile)
+import {readFile, writeFile} from 'node:fs/promises'
+import os from 'node:os'
+import path from 'node:path'
 
 // Hack to get around errors when piping many things to stdout/err
 // (from general-util promisifyProcess)
@@ -72,15 +56,19 @@ async function main() {
         }
       }
     },
+
     'player-options': {type: 'series'},
     'stress-test': {type: 'flag'},
     'socket-client': {type: 'value'},
     'socket-name': {type: 'value'},
     'socket-server': {type: 'value'},
     'telnet-server': {type: 'flag'},
+    'skip-config-file': {type: 'flag'},
+    'config-file': {type: 'value'},
+
     [parseOptions.handleDashless](option) {
       playlistSources.push(option)
-    }
+    },
   })
 
   if (options['player-options'] && !options['player']) {
@@ -88,33 +76,92 @@ async function main() {
     process.exit(1)
   }
 
-  const backend = new Backend({
-    playerName: options['player'],
-    playerOptions: options['player-options']
-  })
+  let jsonConfig = {}
+  let jsonError = null
+
+  const jsonPath =
+    (options['config-file']
+      ? path.resolve(options['config-file'])
+      : path.join(os.homedir(), '.mtui', 'config.json'))
+
+  try {
+    jsonConfig = JSON.parse(await readFile(jsonPath))
+  } catch (error) {
+    if (error.code !== 'ENOENT') {
+      jsonError = error
+    }
+  }
 
-  const result = await backend.setup()
-  if (result.error) {
-    console.error(result.error)
+  if (jsonError) {
+    console.error(`Error loading JSON config:`)
+    console.error(jsonError.message)
+    console.error(`Edit the file below to fix the error, or run mtui with --skip-config-file.`)
+    console.error(jsonPath)
     process.exit(1)
   }
 
-  backend.on('playing', track => {
-    if (track) {
-      writeFile(backend.rootDirectory + '/current-track.txt',
-        getItemPathString(track))
-      writeFile(backend.rootDirectory + '/current-track.json',
-        JSON.stringify(track, null, 2))
-    }
-  })
+  const backendConfig =
+    (options['socket-server']
+      ? {
+          playerName: 'ghost',
+        }
+      : {
+          playerName: options['player'],
+          playerOptions: options['player-options'],
+        })
+
+  const appConfig =
+    (options['socket-server']
+      ? {
+          showPartyControls: true,
+          canControlPlayback: false,
+          canControlQueue: false,
+          canControlQueuePlayers: false,
+          canProcessMetadata: false,
+        }
+   : options['socket-client']
+      ? {
+          showPartyControls: true,
+        }
+      : {})
+
+  const backend = new Backend(backendConfig)
+
+  const setupResult = await backend.setup()
+  if (setupResult.error) {
+    console.error(setupResult.error)
+    process.exit(1)
+  }
+
+  if (options['socket-server']) {
+    const socketServer = makeSocketServer()
+    attachSocketServerToBackend(socketServer, backend)
+    socketServer.listen(options['socket-server'])
+
+    const socketClient = makeSocketClient()
+    attachBackendToSocketClient(backend, socketClient)
+    socketClient.socket.connect(options['socket-server'])
+
+    backend.setPartyNickname('Internal Client')
+    backend.announceJoinParty()
+  }
+
+  if (!options['socket-server']) {
+    backend.on('playing', track => {
+      if (track) {
+        writeFile(backend.rootDirectory + '/current-track.txt',
+          getItemPathString(track))
+        writeFile(backend.rootDirectory + '/current-track.json',
+          JSON.stringify(track, null, 2))
+      }
+    })
+  }
 
   const { appElement, dirtyTerminal, flushable, root } = await setupClient({
     backend,
-    interfacer: new CommandLineInterfacer(),
+    screenInterface: new CommandLineInterface(),
     writable: process.stdout,
-    appConfig: {
-      showPartyControls: !!(options['socket-server'] || options['socket-client'])
-    }
+    appConfig,
   })
 
   appElement.on('quitRequested', () => {
@@ -136,6 +183,20 @@ async function main() {
     root.renderNow()
   })
 
+  if (!options['socket-server'] && playlistSources.length === 0) {
+    if (jsonConfig.defaultPlaylists) {
+      playlistSources.push(...jsonConfig.defaultPlaylists)
+    } else {
+      playlistSources.push({
+        name: 'My ~/Music Library',
+        comment: (
+          '(Add tracks and folders to ~/Music to make them show up here,' +
+          ' or pass mtui your own playlist.json file!)'),
+        source: ['crawl-local', os.homedir() + '/Music']
+      })
+    }
+  }
+
   const loadPlaylists = async () => {
     for (const source of playlistSources) {
       await appElement.loadPlaylistOrSource(source, true)
@@ -151,26 +212,13 @@ async function main() {
     appElement.attachAsServerHost(telnetServer)
   }
 
-  let socketClient
-  let socketServer
-  if (options['socket-server']) {
-    socketServer = makeSocketServer()
-    attachSocketServerToBackend(socketServer, backend)
-    socketServer.listen(options['socket-server'])
-
-    socketClient = makeSocketClient()
-    socketClient.socket.connect(options['socket-server'])
-  }
-
   if (options['socket-client']) {
-    socketClient = makeSocketClient()
+    const socketClient = makeSocketClient()
     const [ p1, p2 ] = options['socket-client'].split(':')
     const host = p2 && p1
     const port = p2 ? p2 : p1
     socketClient.socket.connect(port, host)
-  }
 
-  if (socketClient) {
     attachBackendToSocketClient(backend, socketClient)
 
     let nickname = process.env.USER
@@ -191,6 +239,7 @@ async function main() {
     root.h = h
     root.fixAllLayout()
 
+    /* eslint-disable-next-line no-unused-vars */
     const XXstress = func => '[disabled]'
 
     const stress = func => {