X-Git-Url: https://njoseph.me/gitweb/nimcoon.git/blobdiff_plain/8d06ad6913cf2c0a0714523d6925d3038950f50a..55b0cae73065832a9bce15e7921822fa4172684e:/src/lib.nim?ds=sidebyside diff --git a/src/lib.nim b/src/lib.nim index 0a008b8..62d0553 100644 --- a/src/lib.nim +++ b/src/lib.nim @@ -1,15 +1,17 @@ import htmlparser, httpClient, + json, os, osproc, + re, sequtils, - sugar, - strformat, std/[terminal], strformat, + strformat, strtabs, strutils, + sugar, tables, uri, xmltree @@ -25,9 +27,13 @@ type # poEchoCmd can be added to options for debugging let processOptions = {poStdErrToStdOut, poUsePath} +let PEERTUBE_REGEX = re"videos\/watch\/[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}" + +proc isInstalled(program: string): bool = + execProcess("which " & program).len != 0 proc selectMediaPlayer*(): string = - let availablePlayers = filterIt(supportedPlayers, execProcess("which " & it).len != 0) + let availablePlayers = supportedPlayers.filter(isInstalled) if len(availablePlayers) == 0: stderr.writeLine &"Please install one of the supported media players: {supportedPlayers}" raise newException(OSError, "No supported media player found") @@ -38,7 +44,17 @@ 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 + $response.body + +proc getPeerTubeMagnetLink(url: string): string = + # Gets the magnet link of the best possible resolutino from PeerTube + let uuid = url.substr(find(url, PEERTUBE_REGEX) + "videos/watch/".len) + let domainName = url.substr(8, find(url, '/', start=8) - 1) + let apiURL = &"https://{domainName}/api/v1/videos/{uuid}" + let client = newHttpClient() + let response = get(client, apiURL) + let jsonNode = parseJson($response.body) + jsonNode["files"][0]["magnetUri"].getStr() func extractTitlesAndUrls*(html: string): SearchResults = {.noSideEffect.}: @@ -58,14 +74,14 @@ func isPlaylist(url: string): bool = # This is a pure function with no side effects func buildPlayerArgs(url: string, options: Table[string, bool], player: string): seq[string] = - var args = @[url] - if options["musicOnly"]: args.add("--no-video") - if options["fullScreen"]: args.add("--fullscreen") - # Playlists are only supported for MPV player - if isPlaylist(url) and player == "mpv": - let list_arg = url.split('&')[1] - args[0] = "https://www.youtube.com/playlist?" & list_arg - return args + let url = + # Playlists are only supported for MPV player + if isPlaylist(url) and player == "mpv": + "https://www.youtube.com/playlist?" & url.split('&')[1] + else: url + let musicOnly = if options["musicOnly"]: "--no-video" else: "" + let fullScreen = if options["fullScreen"]: "--fullscreen" else: "" + filterIt([url, musicOnly, fullScreen], it != "") proc play*(player: string, options: Table[string, bool], url: string, title: string = "") = let args = buildPlayerArgs(url, options, player) @@ -78,35 +94,30 @@ proc play*(player: string, options: Table[string, bool], url: string, title: str func buildMusicDownloadArgs*(url: string): seq[string] = {.noSideEffect.}: - var args = @["--ignore-errors", "-f", "bestaudio", "--extract-audio", "--audio-format", "mp3", "--audio-quality", "0", "-o"] let downloadLocation = &"'{expandTilde(musicDownloadDirectory)}/%(title)s.%(ext)s'" - args.add(downloadLocation) - args.add(url) - return args + @["--ignore-errors", "-f", "bestaudio", "--extract-audio", "--audio-format", "mp3", "--audio-quality", "0", "-o", downloadLocation, url] func buildVideoDownloadArgs*(url: string): seq[string] = {.noSideEffect.}: - var args = @["-f", "best", "-o"] let downloadLocation = &"'{expandTilde(videoDownloadDirectory)}/%(title)s.%(ext)s'" - args.add(downloadLocation) - args.add(url) - return args + @["-f", "best", "-o", downloadLocation, url] proc download*(args: openArray[string], title: string) = styledEcho "\n", fgGreen, "Downloading ", styleBright, fgMagenta, title discard execShellCmd(&"youtube-dl {args.join(\" \")}") -func urlLongen(url: string): string = - url.replace("youtu.be/", "www.youtube.com/watch?v=") +func urlLongen(url: string): string = url.replace("youtu.be/", "www.youtube.com/watch?v=") -func stripZshEscaping(url: string): string = - url.replace("\\", "") +func stripZshEscaping(url: string): string = url.replace("\\", "") -func sanitizeURL*(url: string): string = - urlLongen(stripZshEscaping(url)) +func sanitizeURL*(url: string): string = urlLongen(stripZshEscaping(url)) proc directPlay*(url: string, player: string, options: Table[string, bool]) = - if url.startswith("magnet:"): + let url = + if find(url, PEERTUBE_REGEX) != -1 and isInstalled("webtorrent"): + getPeerTubeMagnetLink(url) + else: url + if url.startswith("magnet:") or url.endswith(".torrent"): if options["musicOnly"]: # TODO Replace with WebTorrent once it supports media player options discard execShellCmd(&"peerflix '{url}' -a --{player} -- --no-video") @@ -139,9 +150,10 @@ proc handleUserInput(searchResult: SearchResult, options: Table[string, bool], p play(player, options, searchResult.url, searchResult.title) proc present*(searchResults: SearchResults, options: Table[string, bool], selectionRange: SelectionRange, player: string) = - #[ Continuously present options till the user quits the application - selectionRange: Currently available range to choose from depending on pagination - ]# + ##[ Continuously present options till the user quits the application + + selectionRange: Currently available range to choose from depending on pagination + ]## let userInput = offerSelection(searchResults, options, selectionRange)