]>
Commit | Line | Data |
---|---|---|
44978125 JN |
1 | import htmlparser |
2 | import httpClient | |
4827df7a | 3 | import parseopt |
44978125 | 4 | import osproc |
2f3c8875 | 5 | import sequtils, sugar |
b40b7243 | 6 | import strformat |
3d5bf3fd | 7 | import std/[terminal] |
44978125 JN |
8 | import strtabs |
9 | import strutils | |
10 | import uri | |
11 | import xmltree | |
44978125 | 12 | |
2f0b8428 | 13 | import preferences |
c760b5d9 | 14 | |
2f3c8875 JN |
15 | type SearchResult = tuple[title: string, url: string] |
16 | ||
933e339b JN |
17 | proc selectMediaPlayer(): string = |
18 | let availablePlayers = filterIt(supportedPlayers, execProcess("which " & it).len != 0) | |
19 | if len(availablePlayers) == 0: | |
b40b7243 | 20 | stderr.writeLine &"Please install one of the supported media players: {supportedPlayers}" |
933e339b JN |
21 | raise newException(OSError, "No supported media player found") |
22 | else: | |
23 | return availablePlayers[0] | |
44978125 | 24 | |
39a495a9 JN |
25 | proc getYoutubePage(searchQuery: string): string = |
26 | let queryParam = encodeUrl(searchQuery) | |
485b1053 | 27 | let client = newHttpClient() |
b40b7243 | 28 | let response = get(client, &"https://www.youtube.com/results?hl=en&search_query={queryParam}") |
485b1053 | 29 | return $response.body |
44978125 | 30 | |
2f3c8875 | 31 | proc extractTitlesAndUrls(htmlFile: string): seq[SearchResult] = |
485b1053 | 32 | parseHtml(htmlFile).findAll("a"). |
44978125 | 33 | filter(a => "watch" in a.attrs["href"] and a.attrs.hasKey "title"). |
c760b5d9 | 34 | map(a => (a.attrs["title"], "https://www.youtube.com" & a.attrs["href"]))[..(limit-1)] |
44978125 | 35 | |
2f3c8875 | 36 | proc presentVideoOptions(searchResults: seq[SearchResult]) = |
efcc0441 | 37 | echo "" |
2f3c8875 | 38 | for index, (title, url) in searchResults: |
3d5bf3fd | 39 | styledEcho $index, ". ", styleBright, fgMagenta, title, "\n", resetStyle, fgCyan, url, "\n" |
44978125 | 40 | |
84d84780 JN |
41 | let player = selectMediaPlayer() |
42 | ||
4827df7a JN |
43 | var searchQuery = "" |
44 | var musicOnly = false | |
f135dfc7 | 45 | var feelingLucky = false |
4827df7a JN |
46 | |
47 | for kind, key, value in getopt(): | |
48 | case kind | |
49 | of cmdArgument: | |
50 | searchQuery = key | |
51 | of cmdShortOption, cmdLongOption: | |
52 | case key | |
53 | of "m", "music": musicOnly = true | |
f135dfc7 | 54 | of "l", "lucky": feelingLucky = true |
4827df7a JN |
55 | of cmdEnd: |
56 | discard | |
57 | ||
4827df7a JN |
58 | |
59 | if "https://www.youtube.com" in searchQuery: | |
60 | discard execProcess(&"{player} {searchQuery}") | |
84d84780 JN |
61 | quit(0) |
62 | ||
4827df7a JN |
63 | |
64 | let searchResults = extractTitlesAndUrls(getYoutubePage(searchQuery)) | |
efcc0441 | 65 | |
f135dfc7 JN |
66 | let number = |
67 | if feelingLucky: | |
68 | 0 | |
69 | else: | |
70 | presentVideoOptions(searchResults) | |
71 | stdout.styledWrite(fgYellow, "Choose video number: ") | |
72 | parseInt(readLine(stdin)) | |
efcc0441 | 73 | |
3d5bf3fd | 74 | styledEcho "\n", fgGreen, "Playing ", styleBright, fgMagenta, searchResults[number].title |
efcc0441 | 75 | |
a2319a3f JN |
76 | var command = @[player, searchResults[number].url] |
77 | ||
78 | if musicOnly: | |
79 | command.add("--no-video") | |
80 | ||
3d5bf3fd | 81 | # Play the video using the preferred/available media player |
a2319a3f | 82 | discard execProcess(command.join(" ")) |