]>
Commit | Line | Data |
---|---|---|
1 | import | |
2 | os, | |
3 | parseopt, | |
4 | std/[terminal], | |
5 | strformat, | |
6 | strutils, | |
7 | tables | |
8 | ||
9 | import config | |
10 | import lib | |
11 | ||
12 | ||
13 | proc parseArguments(): CommandLineOptions = | |
14 | var | |
15 | searchQuery = "" | |
16 | options = to_table({"musicOnly": false, "feelingLucky": false, "fullScreen": false, "download": false}) | |
17 | ||
18 | for kind, key, value in getopt(): | |
19 | case kind | |
20 | of cmdArgument: | |
21 | searchQuery = key | |
22 | of cmdShortOption, cmdLongOption: | |
23 | case key | |
24 | of "m", "music": options["musicOnly"] = true | |
25 | of "l", "lucky": options["feelingLucky"] = true | |
26 | of "f", "full-screen": options["fullScreen"] = true | |
27 | of "d", "download": options["download"] = true | |
28 | of cmdEnd: discard | |
29 | ||
30 | return (searchQuery, options) | |
31 | ||
32 | ||
33 | proc isValidOptions*(options: Options): bool = | |
34 | # Check for invalid combinations of options | |
35 | var invalidCombinations = [("musicOnly", "fullScreen")] | |
36 | for combination in invalidCombinations: | |
37 | if options[combination[0]] and options[combination[1]]: | |
38 | stderr.writeLine fmt"Incompatible options provided: {combination[0]} and {combination[1]}" | |
39 | return false | |
40 | return true | |
41 | ||
42 | ||
43 | proc main() = | |
44 | let | |
45 | player = selectMediaPlayer() | |
46 | (searchQuery, options) = parseArguments() | |
47 | ||
48 | if(not isValidOptions(options)): | |
49 | quit(1) | |
50 | ||
51 | if searchQuery.startswith("https:") or searchQuery.startswith("magnet:"): | |
52 | directPlay(searchQuery, player) | |
53 | quit(0) | |
54 | ||
55 | let searchResults = extractTitlesAndUrls(getYoutubePage(searchQuery)) | |
56 | ||
57 | proc getUserInput(): string = | |
58 | if options["feelingLucky"]: "0" | |
59 | else: | |
60 | presentVideoOptions(searchResults[..(limit-1)]) | |
61 | stdout.styledWrite(fgYellow, "Choose video number: ") | |
62 | readLine(stdin) | |
63 | ||
64 | # This is a pure function with no side effects | |
65 | func buildPlayerArgs(number: int): seq[string] = | |
66 | var args = @[searchResults[number].url] | |
67 | if options["musicOnly"]: args.add("--no-video") | |
68 | if options["fullScreen"]: args.add("--fullscreen") | |
69 | return args | |
70 | ||
71 | func buildMusicDownloadArgs(number: int): seq[string] = | |
72 | {.noSideEffect.}: | |
73 | var args = @["--ignore-errors", "-f", "bestaudio", "--extract-audio", "--audio-format", "mp3", "--audio-quality", "0", "-o"] | |
74 | let downloadLocation = &"'{expandTilde(musicDownloadDirectory)}/{searchResults[number].title}.mp3'" | |
75 | args.add(downloadLocation) | |
76 | args.add(searchResults[number].url) | |
77 | return args | |
78 | ||
79 | func buildVideoDownloadArgs(number: int): seq[string] = | |
80 | {.noSideEffect.}: | |
81 | var args = @["-f", "best", "-o"] | |
82 | let downloadLocation = &"'{expandTilde(videoDownloadDirectory)}/%(title)s.%(ext)s'" | |
83 | args.add(downloadLocation) | |
84 | args.add(searchResults[number].url) | |
85 | return args | |
86 | ||
87 | proc handleUserInput(number: int) = | |
88 | if options["download"]: | |
89 | if options["musicOnly"]: | |
90 | download(buildMusicDownloadArgs(number), searchResults[number].title) | |
91 | else: | |
92 | download(buildVideoDownloadArgs(number), searchResults[number].title) | |
93 | else: | |
94 | play(player, buildPlayerArgs(number), searchResults[number].title) | |
95 | ||
96 | ||
97 | while(true): | |
98 | let userInput = getUserInput() | |
99 | ||
100 | if userInput == "all": | |
101 | for number in 0..(len(searchResults)): | |
102 | # TODO `spawn` this? | |
103 | handleUserInput(number) | |
104 | ||
105 | if userInput == "q": | |
106 | break | |
107 | ||
108 | # Play the video using the preferred/available media player | |
109 | let videoNumber = parseInt(userInput) | |
110 | handleUserInput(videoNumber) | |
111 | if options["feelingLucky"]: | |
112 | break | |
113 | ||
114 | ||
115 | when isMainModule: | |
116 | main() |