summary refs log tree commit diff stats
path: root/pkg/unsplash/unsplash.go
blob: 7cd408a68362f277a33b72936a26ee5a070f019f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Copyright (c) 2020, Andinus <andinus@inventati.org>

// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.

// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

package unsplash

import (
	"fmt"
	"net/http"
	"time"

	"framagit.org/andinus/cetus/pkg"
)

// SetFromID sets background from Unsplash Photo ID
func SetFromID(photoID string, width int, height int) error {
	var path string
	var err error

	path = getPathFromID(photoID)
	path = appendSizeToPath(path, width, height)
	err = background.Set(path)
	return err
}

// SetRandom sets a random photo as background
func SetRandom(width int, height int) error {
	var path string
	var err error

	path, err = getPathRandom(width, height)
	if err != nil {
		return err
	}
	err = background.Set(path)
	return err
}

func getPathFromID(photoID string) string {
	var path string
	path = fmt.Sprintf("%s/%s", "https://source.unsplash.com", photoID)
	return path
}

func getPathRandom(width int, height int) (string, error) {
	var err error
	var path string
	var reqPath string

	client := http.Client{
		Timeout: time.Second * 64,
	}

	reqPath = "https://source.unsplash.com"
	reqPath = appendSizeToPath(reqPath, width, height)

	req, err := http.NewRequest(http.MethodGet, reqPath, nil)
	if err != nil {
		return "", err
	}

	res, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	// Unsplash Source redirects to the photo
	path = res.Request.URL.String()
	return path, nil
}

func appendSizeToPath(path string, width int, height int) string {
	var size string

	size = fmt.Sprintf("%dx%d", width, height)
	path = fmt.Sprintf("%s/%s", path, size)
	return path
}
use click triggers an action that disables curses and ## starts curses again, (e.g. running a ## file by clicking on its ## preview) and the next key is another mouse click, the bstate of this ## mouse event will be invalid. (atm, invalid bstates are recognized ## as scroll-down, so this avoids an errorneous scroll-down action) curses.ungetmouse(0,0,0,0,0) else: curses.mousemask(0) class UI(DisplayableContainer): is_set_up = False load_mode = False is_on = False termsize = None def __init__(self, env=None, fm=None): self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) self.redrawlock = threading.Event() self.redrawlock.set() if fm is not None: self.fm = fm def setup_curses(self): os.environ['ESCDELAY'] = '25' # don't know a cleaner way try: self.win = curses.initscr() except _curses.error as e: if e.args[0] == "setupterm: could not find terminal": os.environ['TERM'] = 'linux' self.win = curses.initscr() self.keymaps.use_keymap('browser') DisplayableContainer.__init__(self, None) def initialize(self): """initialize curses, then call setup (at the first time) and resize.""" self.win.leaveok(0) self.win.keypad(1) self.load_mode = False curses.cbreak() curses.noecho() curses.halfdelay(20) try: curses.curs_set(int(bool(self.settings.show_cursor))) except: pass curses.start_color() try: curses.use_default_colors() except: pass self.settings.signal_bind('setopt.mouse_enabled', _setup_mouse) _setup_mouse(dict(value=self.settings.mouse_enabled)) if not self.is_set_up: self.is_set_up = True self.setup() self.win.addstr("loading...") self.win.refresh() self._draw_title = curses.tigetflag('hs') # has_status_line self.update_size() self.is_on = True if self.settings.update_tmux_title: sys.stdout.write("\033kranger\033\\") sys.stdout.flush() def suspend(self): """Turn off curses""" self.win.keypad(0) curses.nocbreak() curses.echo() try: curses.curs_set(1) except: pass if self.settings.mouse_enabled: _setup_mouse(dict(value=False)) curses.endwin() self.is_on = False def set_load_mode(self, boolean): boolean = bool(boolean) if boolean != self.load_mode: self.load_mode = boolean if boolean: # don't wait for key presses in the load mode curses.cbreak() self.win.nodelay(1) else: self.win.nodelay(0) # Sanitize halfdelay setting halfdelay = min(255, max(1, self.settings.idle_delay // 100)) curses.halfdelay(halfdelay) def destroy(self): """Destroy all widgets and turn off curses""" DisplayableContainer.destroy(self) self.suspend() def handle_mouse(self): """Handles mouse input""" try: event = MouseEvent(curses.getmouse()) except _curses.error: return if not self.console.visible: DisplayableContainer.click(self, event) def handle_key(self, key): """Handles key input""" if hasattr(self, 'hint'): self.hint() if key < 0: self.keybuffer.clear() elif not DisplayableContainer.press(self, key): self.keymaps.use_keymap('browser') self.press(key) def press(self, key): keybuffer = self.keybuffer self.status.clear_message() keybuffer.add(key) self.fm.hide_bookmarks() self.browser.draw_hints = not keybuffer.finished_parsing \ and keybuffer.finished_parsing_quantifier if keybuffer.result is not None: try: self.fm.execute_console(keybuffer.result, wildcards=keybuffer.wildcards, quantifier=keybuffer.quantifier) finally: if keybuffer.finished_parsing: keybuffer.clear() elif keybuffer.finished_parsing: keybuffer.clear() return False return True def handle_keys(self, *keys): for key in keys: self.handle_key(key) def handle_input(self): key = self.win.getch() if key is 27 or key >= 128 and key < 256: # Handle special keys like ALT+X or unicode here: keys = [key] previous_load_mode = self.load_mode self.set_load_mode(True) for n in range(4): getkey = self.win.getch() if getkey is not -1: keys.append(getkey) if len(keys) == 1: keys.append(-1) elif keys[0] == 27: keys[0] = ALT_KEY if self.settings.xterm_alt_key: if len(keys) == 2 and keys[1] in range(127, 256): if keys[0] == 195: keys = [ALT_KEY, keys[1] - 64] elif keys[0] == 194: keys = [ALT_KEY, keys[1] - 128] self.handle_keys(*keys) self.set_load_mode(previous_load_mode) if self.settings.flushinput and not self.console.visible: curses.flushinp() else: # Handle simple key presses, CTRL+X, etc here: if key >= 0: if self.settings.flushinput and not self.console.visible: curses.flushinp() if key == curses.KEY_MOUSE: self.handle_mouse() elif key == curses.KEY_RESIZE: self.update_size() else: if not self.fm.input_is_blocked(): self.handle_key(key) def setup(self): """Build up the UI by initializing widgets.""" from ranger.gui.widgets.browserview import BrowserView from ranger.gui.widgets.titlebar import TitleBar from ranger.gui.widgets.console import Console from ranger.gui.widgets.statusbar import StatusBar from ranger.gui.widgets.taskview import TaskView from ranger.gui.widgets.pager import Pager from ranger.ext.vcs import VcsThread # Create a title bar self.titlebar = TitleBar(self.win) self.add_child(self.titlebar) # Create the browser view self.browser = BrowserView(self.win, self.settings.column_ratios) self.settings.signal_bind('setopt.column_ratios', self.browser.change_ratios) self.add_child(self.browser) # Create the process manager self.taskview = TaskView(self.win) self.taskview.visible = False self.add_child(self.taskview) # Create the status bar self.status = StatusBar(self.win, self.browser.main_column) self.add_child(self.status) # Create the console self.console = Console(self.win) self.add_child(self.console) self.console.visible = False # Create the pager self.pager = Pager(self.win) self.pager.visible = False self.add_child(self.pager) # Create VCS thread self.vcsthread = VcsThread(self, self.settings.idle_delay) self.vcsthread.start() def redraw(self): """Redraw all widgets""" self.redrawlock.wait() self.redrawlock.clear() self.poke() # determine which widgets are shown if self.console.wait_for_command_input or self.console.question_queue: self.console.focused = True self.console.visible = True self.status.visible = False else: self.console.focused = False self.console.visible = False self.status.visible = True self.draw() self.finalize() self.redrawlock.set() def redraw_window(self): """Redraw the window. This only calls self.win.redrawwin().""" self.win.erase() self.win.redrawwin() self.win.refresh() self.win.redrawwin() self.need_redraw = True def update_size(self): """resize all widgets""" self.termsize = self.win.getmaxyx() y, x = self.termsize self.browser.resize(self.settings.status_bar_on_top and 2 or 1, 0, y - 2, x) self.taskview.resize(1, 0, y - 2, x) self.pager.resize(1, 0, y - 2, x) self.titlebar.resize(0, 0, 1, x) self.status.resize(self.settings.status_bar_on_top and 1 or y-1, 0, 1, x) self.console.resize(y - 1, 0, 1, x) def draw(self): """Draw all objects in the container""" self.win.touchwin() DisplayableContainer.draw(self) if self._draw_title and self.settings.update_title: cwd = self.fm.thisdir.path if cwd.startswith(self.fm.home_path): cwd = '~' + cwd[len(self.fm.home_path):] if self.settings.shorten_title: split = cwd.rsplit(os.sep, self.settings.shorten_title) if os.sep in split[0]: cwd = os.sep.join(split[1:]) try: fixed_cwd = cwd.encode('utf-8', 'surrogateescape'). \ decode('utf-8', 'replace') sys.stdout.write("%sranger:%s%s" % (curses.tigetstr('tsl').decode('latin-1'), fixed_cwd, curses.tigetstr('fsl').decode('latin-1'))) sys.stdout.flush() except: pass self.win.refresh() def finalize(self): """Finalize every object in container and refresh the window""" DisplayableContainer.finalize(self) self.win.refresh() def draw_images(self): if self.pager.visible: self.pager.draw_image() elif self.browser.pager.visible: self.browser.pager.draw_image() else: self.browser.columns[-1].draw_image() def close_pager(self): if self.console.visible: self.console.focused = True self.pager.close() self.pager.visible = False self.pager.focused = False self.browser.visible = True def open_pager(self): self.browser.columns[-1].clear_image(force=True) if self.console.focused: self.console.focused = False self.pager.open() self.pager.visible = True self.pager.focused = True self.browser.visible = False return self.pager def open_embedded_pager(self): self.browser.open_pager() for column in self.browser.columns: if column == self.browser.main_column: break column.level_shift(amount=1) return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() for column in self.browser.columns: column.level_restore() def open_console(self, string='', prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None def close_console(self): self.console.close() self.close_pager() def open_taskview(self): self.browser.columns[-1].clear_image(force=True) self.pager.close() self.pager.visible = False self.pager.focused = False self.console.visible = False self.browser.visible = False self.taskview.visible = True self.taskview.focused = True def redraw_main_column(self): self.browser.main_column.need_redraw = True def close_taskview(self): self.taskview.visible = False self.browser.visible = True self.taskview.focused = False def throbber(self, string='.', remove=False): if remove: self.titlebar.throbber = type(self.titlebar).throbber else: self.titlebar.throbber = string def hint(self, text=None): self.status.hint = text def get_pager(self): if self.browser.pager.visible: return self.browser.pager else: return self.pager