Skip to content

Commit

Permalink
added vim-like behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
intnull committed Jul 25, 2011
1 parent e50b270 commit dc0916d
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 48 deletions.
46 changes: 32 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,39 @@
This program is still under heavy development!

# DESCRIPTION
**Videotop** is an open source command line browser for online videos, written in python with vim-like keybindings.
**Videotop** is a free console browser for online videos, written in python with vim-like keybindings.

It uses the following external python modules:

# USAGE
If you are already familiar with vim the controls should be pretty intuitive.
There are two modes: command mode and browse mode.

In command mode you can search for videos by typing **:s** *VIDEOSEARCH* and hitting **ENTER**.
This will generate a list of videos and switch to browse mode.

In browse mode you can download the videos by hitting **ENTER** and play them with **p**.
You can also open the youtube page by hitting **o**.
**CTRL n** lists the next videos of your previous search and **CTRL r** clears the screen.

# COMMAND TABLE
<table border='1'>
<tr><th>Command Mode</th><th>Browse Mode</th><th>Description</th></tr>
<tr><td>:search, :s</td><td>s</td><td>Search for videos and switch to browse mode</td></tr>
<tr><td>:clear</td><td>CTRL r</td><td>Clear the video list and switch to command mode</td></tr>
<tr><td>:videos, :v</td><td></td><td>Show the downloaded videos and switch to browse mode</td></tr>
<tr><td>:13</td><td></td><td>Select video 13 and switch to browse mode</td></tr>
<tr><td></td><td>CTRL n</td><td>List the next videos of the previous search</td></tr>
<tr><td></td><td>ENTER</td><td>Download the selected video</td></tr>
<tr><td></td><td>o</td><td>Open the youtube site of the selected video in firefox</td></tr>
<tr><td></td><td>p</td><td>Play the selected video with mplayer</td></tr>
<tr><td></td><td>j</td><td>Move down</td></tr>
<tr><td></td><td>k</td><td>Move up</td></tr>
<tr><td></td><td>CTRL d</td><td>Move down</td></tr>
<tr><td></td><td>CTRL u</td><td>Move up</td></tr>
<tr><td></td><td>g</td><td>Move to the first video</td></tr>
<tr><td></td><td>G</td><td>Move to the last video</td></tr>
</table>

# DEPENDENCIES
* [urwid][1] to provide an ncurses frontend.
* [gdata][2] and [youtube-dl][3] to search for and download youtube videos.
* (optional) [mplayer][4] to play the downloaded videos.
Expand All @@ -14,14 +43,3 @@ It uses the following external python modules:
[2]: http://code.google.com/apis/youtube/1.0/developers_guide_python.html
[3]: http://rg3.github.com/youtube-dl/
[4]: http://www.mplayerhq.hu/

# USAGE
If you are already familiar with vim the controls should be pretty intuitive.
There are two different modes: command mode and browse mode.
Press TAB to toggle between the two.

In command mode you can search for videos by hitting enter.
This will generate a list of videos and switch to browse mode.

In browse mode you can download the videos by hitting **ENTER** and play them by hitting **p**.
You can also open the youtube page by hitting **o**. To list more videos of your previous search hit **CTRL n** and to clear the video list hit **CTRL r**.
Binary file modified screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 65 additions & 34 deletions videotop.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@
import youtube_client

class VideoButton(urwid.FlowWidget):
def __init__(self, video, index):
def __init__(self, video, index, color='index'):
self.video = video
self.index = urwid.Text(('index', str(index)))
self.index = urwid.Text((color, str(index)))
try:
rounded_rating = str(round(float(self.video.rating), 1))
except:
rounded_rating = self.video.rating

width = 30
views = urwid.Text([('index', 'Views: '), self.video.views])
rating = urwid.Text([('index', 'Rating: '), rounded_rating])
author = urwid.Text([('index', 'Author: '), self.video.author, '\n'])
button_info = urwid.Columns([('fixed', width, author), ('fixed', width, views), ('fixed', width, rating)])
duration = self.video.formatted_duration()
views = urwid.Text([(color, 'Views: '), self.video.views])
rating = urwid.Text([(color, 'Rating: '), rounded_rating])
author = urwid.Text([(color, 'Author: '), self.video.author])
duration = urwid.Text([(color, 'Duration: '), duration, '\n'])
button_info = urwid.Columns([('fixed', width, author), ('fixed', width, views),
('fixed', width, rating), ('fixed', width, duration)])
title = urwid.Text(self.video.title)
button = urwid.Pile([title, button_info])

Expand Down Expand Up @@ -51,20 +54,50 @@ def keypress(self, size, key):
return key

class CommandPrompt(urwid.Edit):
def clear(self):
self.set_caption('')
self.set_edit_text('')
def keypress(self, size, key):
if key == 'enter' and not self.get_edit_text() == '':
query = self.get_edit_text()
self.set_edit_text('')
status_bar.set_text('Searching for: ' + query)
loop.draw_screen()
search = client.search(query) # takes the most time
listbox.append(search)
status_bar.set_text(query)
main_frame.set_focus('body')
command = self.get_edit_text()
command = command.split(' ', 1)
if command[0] in ('search', 's'):
query = command[1]
self.clear()
status_bar.set_text('Searching for: ' + query)
loop.draw_screen()
search = client.search(query) # takes the most time
listbox.append(search)
status_bar.set_text(query)
main_frame.set_focus('body')
elif command[0] in ('videos', 'v'):
self.clear()
status_bar.set_text('Listing local videos')
loop.draw_screen()
video_list = os.listdir(os.getcwd())
video_list = [os.path.splitext(video)[0] for video in video_list]
video_list.sort()
videos = [client.get_local_video(video) for video in video_list]
listbox.append(videos, color='local_video')
main_frame.set_focus('body')
elif command[0] == 'clear':
listbox.clear()
self.set_edit_text('')
elif command[0].isdigit():
self.clear()
video_focus = int(command[0]) - 1
listbox.set_focus(video_focus)
main_frame.set_focus('body')
elif command[0] in ('quit', 'q'):
raise urwid.ExitMainLoop()
elif command[0] == '?':
listbox.search(command[1])
else:
status_bar.set_text('Error, there is no command named "' + command[0] + '"')
pass
if key == 'ctrl x':
main_frame.set_focus('body')
self.set_caption('')
self.set_edit_text('')
self.clear()
else:
return urwid.Edit.keypress(self, size, key)

Expand All @@ -73,11 +106,22 @@ def __init__(self):
self.body = urwid.SimpleListWalker([])
self.listbox = urwid.ListBox(self.body)
urwid.WidgetWrap.__init__(self, self.listbox)
def append(self, search):
def append(self, search, color='index'):
for video in search:
new_button = VideoButton(video, int(len(self.body)) + 1)
new_button = VideoButton(video, int(len(self.body)) + 1, color)
self.body.append(new_button)
loop.draw_screen()
def clear(self):
status_bar.set_text('Cleared the screen.')
self.body[:] = []
def set_focus(self, position):
self.listbox.set_focus(position)
def search(self, pattern):
video_list = [video_button.video.title for video_button in self.body]
for video in video_list:
if pattern in video:
status_bar.set_text('found: ' + pattern)
# TODO: return the list of all indexes whose videos have the pattern in them.
def keypress(self, size, key):
if key == ':':
main_frame.set_focus('footer')
Expand All @@ -99,9 +143,7 @@ def keypress(self, size, key):
position = 0
self.listbox.set_focus(position, 'below')
elif key == 'ctrl r':
status_bar.set_text('Cleared the screen.')
self.body[:] = []
main_frame.set_focus('footer')
self.clear()
elif key == 'ctrl n':
search = client.next_page()
self.append(search)
Expand All @@ -117,6 +159,7 @@ def keypress(self, size, key):
('status', 'white', 'dark blue'),
('opened', 'light blue', 'black'),
('downloaded', 'white', 'black'),
('local_video', 'yellow', 'black'),
('index', 'dark cyan', 'black')]
listbox = VideoListBox()
command_prompt = CommandPrompt(':')
Expand All @@ -128,19 +171,7 @@ def keypress(self, size, key):
client = youtube_client.YouTubeClient()

def handle_input(input):
if input in ('q', 'Q'):
raise urwid.ExitMainLoop()
if input == 'tab':
if main_frame.focus_part == 'body':
command_prompt.set_caption(':')
main_frame.set_focus('footer')
else:
main_frame.set_focus('body')
if input == 'm':
video_list = os.listdir(os.getcwd())
video_list = [os.path.splitext(video)[0] for video in video_list]
videos = [client.get_local_video(video) for video in video_list]
listbox.append(videos)
pass

loop = urwid.MainLoop(main_frame, palette, unhandled_input=handle_input)
loop.run()
10 changes: 10 additions & 0 deletions youtube_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def __init__(self, entry):
self.author = entry.author[0].name.text
except:
self.author = 'N/A' # dunno, local video
self.duration = 'N/A'
try:
self.views = entry.statistics.view_count
except AttributeError:
Expand Down Expand Up @@ -82,3 +83,12 @@ def play(self):
subprocess.Popen(['mplayer', '-fs', self.file], stdout=temp, stderr=temp, stdin=temp)
self.file = self.title + '.mp4'
subprocess.Popen(['mplayer', '-fs', self.file], stdout=temp, stderr=temp, stdin=temp)

def formatted_duration(self):
try:
m, s = divmod(int(self.duration), 60)
h, m = divmod(m, 60)
test = "%d:%02d:%02d" % (h, m, s)
return test
except:
return self.duration # N/A

0 comments on commit dc0916d

Please sign in to comment.