From: Joseph Nuthalapati Date: Fri, 5 Jun 2020 18:50:08 +0000 (+0530) Subject: Add config option to rewrite invidio.us URLs X-Git-Tag: 0.5.0~9 X-Git-Url: https://njoseph.me/gitweb/nimcoon.git/commitdiff_plain/b44b64940a9a5708a58decce73634c81ef0b9783 Add config option to rewrite invidio.us URLs --- diff --git a/src/config.nim b/src/config.nim index 3593fe6..de8be3f 100644 --- a/src/config.nim +++ b/src/config.nim @@ -12,3 +12,7 @@ let videoDownloadDirectory* = "~/Videos" # Download music to this directory let musicDownloadDirectory* = "~/Music" + +# Rewrite Invidious URLs to YouTube +# Using Invidious as a proxy makes loading YouTube videos much slower +let rewriteInvidiousURLs* = false diff --git a/src/lib.nim b/src/lib.nim index 62d0553..ccd1a39 100644 --- a/src/lib.nim +++ b/src/lib.nim @@ -18,6 +18,7 @@ import import config + type Options* = Table[string, bool] SearchResult* = tuple[title: string, url: string] @@ -25,13 +26,17 @@ type CommandLineOptions* = tuple[searchQuery: string, options: Options] SelectionRange* = tuple[begin: int, until: int] + # 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}" +let + processOptions = {poStdErrToStdOut, poUsePath} + 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 = supportedPlayers.filter(isInstalled) if len(availablePlayers) == 0: @@ -40,12 +45,14 @@ proc selectMediaPlayer*(): string = 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}") $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) @@ -56,26 +63,29 @@ proc getPeerTubeMagnetLink(url: string): string = let jsonNode = parseJson($response.body) jsonNode["files"][0]["magnetUri"].getStr() + func extractTitlesAndUrls*(html: string): SearchResults = {.noSideEffect.}: 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"])) + proc presentVideoOptions*(searchResults: SearchResults) = eraseScreen() for index, (title, url) in searchResults: styledEcho $index, ". ", styleBright, fgMagenta, title, "\n", resetStyle, fgCyan, url, "\n" + func isPlaylist(url: string): bool = - # Identifies if video is part of a playlist - # Only YouTube playlists are supported for now + ##[ Identifies if video is part of a playlist. + Only YouTube playlists are supported for now. ]## "www.youtube.com" in url and "&list=" in url -# This is a pure function with no side effects + func buildPlayerArgs(url: string, options: Table[string, bool], player: string): seq[string] = let url = - # Playlists are only supported for MPV player + # Playlists are only supported by MPV player. VLC needs a plugin. if isPlaylist(url) and player == "mpv": "https://www.youtube.com/playlist?" & url.split('&')[1] else: url @@ -83,6 +93,7 @@ func buildPlayerArgs(url: string, options: Table[string, bool], player: string): 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) if title != "": @@ -92,25 +103,39 @@ proc play*(player: string, options: Table[string, bool], url: string, title: str else: discard execProcess(player, args=args, options=processOptions) -func buildMusicDownloadArgs*(url: string): seq[string] = + +func buildMusicDownloadArgs(url: string): seq[string] = {.noSideEffect.}: let downloadLocation = &"'{expandTilde(musicDownloadDirectory)}/%(title)s.%(ext)s'" - @["--ignore-errors", "-f", "bestaudio", "--extract-audio", "--audio-format", "mp3", "--audio-quality", "0", "-o", downloadLocation, url] + @["--ignore-errors", "-f", "bestaudio", "--extract-audio", "--audio-format", "mp3", + "--audio-quality", "0", "-o", downloadLocation, url] + -func buildVideoDownloadArgs*(url: string): seq[string] = +func buildVideoDownloadArgs(url: string): seq[string] = {.noSideEffect.}: let downloadLocation = &"'{expandTilde(videoDownloadDirectory)}/%(title)s.%(ext)s'" @["-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 rewriteInvidiousToYouTube(url: string): string = + {.noSideEffect.}: + if rewriteInvidiousURLs: url.replace("invidio.us", "www.youtube.com") else: url + + func stripZshEscaping(url: string): string = url.replace("\\", "") -func sanitizeURL*(url: string): string = urlLongen(stripZshEscaping(url)) + +func sanitizeURL*(url: string): string = + rewriteInvidiousToYouTube(urlLongen(stripZshEscaping(url))) + proc directPlay*(url: string, player: string, options: Table[string, bool]) = let url = @@ -127,12 +152,14 @@ proc directPlay*(url: string, player: string, options: Table[string, bool]) = else: play(player, options, url) + proc directDownload*(url: string, musicOnly: bool) = let args = if musicOnly: buildMusicDownloadArgs(url) else: buildVideoDownloadArgs(url) discard execShellCmd(&"youtube-dl {args.join(\" \")}") + proc offerSelection(searchResults: SearchResults, options: Table[string, bool], selectionRange: SelectionRange): string = if options["feelingLucky"]: "0" else: @@ -140,6 +167,7 @@ proc offerSelection(searchResults: SearchResults, options: Table[string, bool], stdout.styledWrite(fgYellow, "Choose video number: ") readLine(stdin) + proc handleUserInput(searchResult: SearchResult, options: Table[string, bool], player: string) = if options["download"]: if options["musicOnly"]: @@ -149,6 +177,7 @@ proc handleUserInput(searchResult: SearchResult, options: Table[string, bool], p else: 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