Modularity and Tests
authorJoseph Nuthalapati <njoseph@riseup.net>
Sun, 12 Jan 2020 06:25:06 +0000 (11:55 +0530)
committerJoseph Nuthalapati <njoseph@riseup.net>
Sun, 12 Jan 2020 06:25:06 +0000 (11:55 +0530)
Signed-off-by: Joseph Nuthalapati <njoseph@riseup.net>
.gitlab-ci.yml
TODO.org
lib.nim [new file with mode: 0644]
nimcoon.nim
tests.nim [new file with mode: 0644]

index 727e2f2f3f5729d076652a36f70fc14ddca2c776..e5efc7163133748eb7c7805cb354fb8c6e263211 100644 (file)
@@ -1,10 +1,14 @@
 image: nimlang/nim:latest
 
 stages:
-  - build
+  - test
+  - publish
 
 compile:
-  stage: build
+  stage: test
+  script:
+    - nim c -d:ssl -r tests
+  stage: publish
   script:
     - nim c -d:ssl -d:release nimcoon.nim && strip nimcoon
   artifacts:
index cf42d0fb5fa0d47d1148d970b758d5daeb04fad6..0019cabd52f03b9f5fe92be064fb28685efdfdc9 100644 (file)
--- a/TODO.org
+++ b/TODO.org
@@ -5,8 +5,7 @@
 - [X] Create a proper CLI
 - [X] PeerTube support (only direct download, because webtorrent seeds are too slow)
 - [X] Find a better name. clitube is an SEO disaster
-- [ ] Terminal color themes?
-- [ ] SoundCloud support?
 - [ ] Spawn video player and quit immediately
+- [ ] SoundCloud support? Search and play music
 - [ ] LRU cache of content so that frequently-played content doesn't use BW
 - [ ] Option to download audio/video
diff --git a/lib.nim b/lib.nim
new file mode 100644 (file)
index 0000000..25669a3
--- /dev/null
+++ b/lib.nim
@@ -0,0 +1,62 @@
+import
+  htmlparser,
+  httpClient,
+  osproc,
+  sequtils,
+  sugar,
+  strformat,
+  std/[terminal],
+  strtabs,
+  strutils,
+  uri,
+  xmltree
+
+import config
+
+type
+  SearchResult* = tuple[title: string, url: string]
+  CommandLineOptions* = tuple[searchQuery: string, musicOnly: bool, feelingLucky: bool, fullScreen: bool]
+
+proc selectMediaPlayer*(): string =
+  let availablePlayers = filterIt(supportedPlayers, execProcess("which " & it).len != 0)
+  if len(availablePlayers) == 0:
+    stderr.writeLine &"Please install one of the supported media players: {supportedPlayers}"
+    raise newException(OSError, "No supported media player found")
+  else:
+    return availablePlayers[0]
+
+proc getYoutubePage*(searchQuery: string): string =
+  let queryParam = encodeUrl(searchQuery)
+  let client = newHttpClient()
+  let response = get(client, &"https://www.youtube.com/results?hl=en&search_query={queryParam}")
+  return $response.body
+
+proc extractTitlesAndUrls*(html: string): seq[SearchResult] =
+  parseHtml(html).findAll("a").
+    filter(a => "watch" in a.attrs["href"] and a.attrs.hasKey "title").
+    map(a => (a.attrs["title"], "https://www.youtube.com" & a.attrs["href"]))[..(limit-1)]
+
+proc presentVideoOptions*(searchResults: seq[SearchResult]) =
+  echo ""
+  for index, (title, url) in searchResults:
+    styledEcho $index, ". ", styleBright, fgMagenta, title, "\n", resetStyle, fgCyan, url, "\n"
+
+proc play*(player: string, args: openArray[string]) =
+  # poEchoCmd can be added to options for debugging
+  discard execProcess(player, args=args, options={poStdErrToStdOut, poUsePath})
+  quit(0)
+
+func urlLongen(url: string): string =
+  url.replace("youtu.be/", "www.youtube.com/watch?v=")
+
+func stripZshEscaping(url: string): string =
+  url.replace("\\", "")
+
+func sanitizeURL*(url: string): string =
+  urlLongen(stripZshEscaping(url))
+
+proc directPlay*(searchQuery: string, player: string) =
+  if "watch?" in searchQuery or "videos/watch" in searchQuery or "soundcloud.com" in searchQuery:
+    play(player, args=[sanitizeURL(searchQuery)])
+  elif searchQuery.startswith("magnet:"):
+    play("peerflix", args=[searchQuery, &"--{player}"])
index 7b69ddb5ab3e8320184054e9e82b17db9bf6c376..5c2dc08520d57900b2bcb2933ba13f51ffcaf48e 100644 (file)
@@ -1,30 +1,9 @@
 import
-  htmlparser,
-  httpClient,
   parseopt,
-  osproc,
-  sequtils,
-  sugar,
-  strformat,
   std/[terminal],
-  strtabs,
-  strutils,
-  uri,
-  xmltree
+  strutils
 
-import config
-
-type
-  SearchResult = tuple[title: string, url: string]
-  CommandLineOptions = tuple[searchQuery: string, musicOnly: bool, feelingLucky: bool, fullScreen: bool]
-
-proc selectMediaPlayer(): string =
-  let availablePlayers = filterIt(supportedPlayers, execProcess("which " & it).len != 0)
-  if len(availablePlayers) == 0:
-    stderr.writeLine &"Please install one of the supported media players: {supportedPlayers}"
-    raise newException(OSError, "No supported media player found")
-  else:
-    return availablePlayers[0]
+import lib
 
 proc parseOptions(): CommandLineOptions =
   var
@@ -47,32 +26,6 @@ proc parseOptions(): CommandLineOptions =
 
   return (searchQuery, musicOnly, feelingLucky, fullScreen)
 
-proc getYoutubePage(searchQuery: string): string =
-  let queryParam = encodeUrl(searchQuery)
-  let client = newHttpClient()
-  let response = get(client, &"https://www.youtube.com/results?hl=en&search_query={queryParam}")
-  return $response.body
-
-proc extractTitlesAndUrls(html: string): seq[SearchResult] =
-  parseHtml(html).findAll("a").
-    filter(a => "watch" in a.attrs["href"] and a.attrs.hasKey "title").
-    map(a => (a.attrs["title"], "https://www.youtube.com" & a.attrs["href"]))[..(limit-1)]
-
-proc presentVideoOptions(searchResults: seq[SearchResult]) =
-  echo ""
-  for index, (title, url) in searchResults:
-    styledEcho $index, ". ", styleBright, fgMagenta, title, "\n", resetStyle, fgCyan, url, "\n"
-
-proc play(player: string, args: openArray[string]) =
-  discard execProcess(player, args=args, options={poStdErrToStdOut, poUsePath, poEchoCmd})
-  quit(0)
-
-proc directPlay(searchQuery: string, player: string) =
-  if "watch?" in searchQuery or "videos/watch" in searchQuery:
-    play(player, args=[searchQuery])
-  elif searchQuery.startswith("magnet:"):
-    play("peerflix", args=[searchQuery, &"--{player}"])
-
 proc main() =
   let
     player = selectMediaPlayer()
@@ -102,4 +55,5 @@ proc main() =
   # Play the video using the preferred/available media player
   play(player, buildArgs())
 
-main()
+when isMainModule:
+  main()
diff --git a/tests.nim b/tests.nim
new file mode 100644 (file)
index 0000000..f24eb18
--- /dev/null
+++ b/tests.nim
@@ -0,0 +1,11 @@
+import unittest
+
+import lib
+
+suite "Playing direct links":
+
+  test "sanitize URL":
+    # give up and stop if this fails
+    let expected = "https://www.youtube.com/watch?v=QOEMv0S8AcA"
+    check(sanitizeURL("https://youtu.be/QOEMv0S8AcA") == expected)
+    check(sanitizeURL("https://www.youtube.com/watch\\?v\\=QOEMv0S8AcA") == expected)