joe di castrohttp://joedicastro.comFri, 19 Oct 2012 22:40:00 +0200Productividad & Linux: Ncduhttp://joedicastro.com/productividad-linux-ncdu.html<p>Esta es una pequeña aplicación que sigue la máxima de <a href="http://es.wikipedia.org/wiki/Douglas_McIlroy">Doug Mcllroy</a> que acabaría resumiendo la filosofía Unix <em>"Escribe programas que hagan una sola cosa y que la hagan bien"</em>. Y siguiendo la línea de los programas que engloban esta serie de productividad sobre Linux, es un programa de consola que se maneja íntegramente con el teclado, y donde además los atajos están inspirados en los de <a href="http://www.vim.org/">Vim</a>.</p> <h2 id="ncdu">Ncdu</h2> <p><a href="http://dev.yorhel.nl/ncdu">Ncdu</a> es un acrónimo para "NCurses Disk Usage", es decir, "Uso de disco con interfaz ncurses". Lo que pretendía <a href="https://github.com/yorhel">Yoran Heling</a>, su autor, cuando creo <strong>ncdu</strong>, era obtener un analizador de uso de disco en consola que fuera lo suficientemente ligero para poder emplearlo en un servidor remoto a través de <a href="https://es.wikipedia.org/wiki/Ssh">ssh</a>. El gran acierto fue emplear la interfaz <a href="https://es.wikipedia.org/wiki/Ncurses">ncurses</a> para poder navegar por los directorios con extrema facilidad al mismo tiempo que se presentaba la información en un formato legible y amigable. El segundo y no menos importante acierto, es emplear los conocidos atajos de teclado de Vim para navegar entre los directorios.</p> <p>El resultado es un analizador de ocupación de disco que es realmente útil, agradable de utilizar y que es tan rápido y ligero que se puede emplear sin interfaz gráfica y en maquinas remotas. Es una gran ayuda para los administradores de sistemas, que hasta ahora nos teníamos que pelear con otras herramientas bastante menos agradables. Es la típica herramienta que cuando la utilizas por primera vez piensas ¿Por qué demonios no la habría encontrado antes?</p> <p style="text-align:center;"><img src="pictures/ncdu.png" width="700" height="559" alt="ncdu" /></p> <p>Como se puede ver la interfaz es muy limpia y carece de elementos superfluos que nos distraigan de lo importante, un pecado que cometen algunas de las aplicaciones gráficas más famosas, que cuentan con unos gráficos muy bonitos, pero realmente no demasiado útiles. Es sencillisima de emplear una vez que conoces los atajos y cuenta con ayuda integrada a la que se accede pulsando <strong><code>?</code></strong>. Incluso para aquellos que no están acostumbrados a navegar empleando las típicas teclas de vim (<strong>h</strong>, <strong>j</strong>, <strong>k</strong>, <strong>l</strong>), se pueden utilizar las teclas de dirección.</p> <h3 id="caracter+sticas">Características</h3> <p>Un programa de este tipo no necesita una funcionalidad muy elevada, pero destacare aquí algunas de las posibilidades que nos ofrece:</p> <ul> <li>Podemos ordenar los directorios/ficheros en función de su nombre o de su tamaño y en orden ascendente o descendente </li> <li>Se pueden eliminar directamente ficheros o directorios desde la aplicación, aunque también podemos iniciarla en modo solo lectura para prevenir borrados accidentales</li> <li>Se muestra o no, el porcentaje de espacio ocupado de forma gráfica y/o numérica</li> <li>El espacio empleado en disco puede hacer referencia al real o al aparente</li> <li>Los directorios y ficheros ocultos pueden ser o no mostrados</li> <li>Nos permite recalcular el espacio ocupado de un directorio concreto sin necesidad de volver a recalcular todo </li> <li>Tenemos la posibilidad de volcar la información a un archivo, que puede también ser leído por el mismo programa</li> <li>Es posible mostrar la información de un elemento individual en un cuadro emergente</li> </ul> <p>La verdad es que lo único que hecho en falta en el programa es quizás un poco de color para distinguir entre ficheros y directorios de forma más visual. Por lo demás, es muy rápido calculando el espacio, no he hecho una comparación directa, pero me parece ligeramente más rápido que Baobab.</p> <h3 id="alternativas">Alternativas</h3> <p>Existen varias alternativas decentes como aplicaciones gráficas, como los conocidos <a href="http://www.marzocca.net/linux/baobab/">Baobab</a> (que viene con las herramientas de Gnome) o <a href="http://www.jgoodies.com/freeware/jdiskreport/">JDiskReport</a>. Después existen múltiples alternativas tanto en modo gráfico como en modo consola que, sinceramente, no puedo recomendar a nadie, bien porque son más vistosos que prácticos o bien porque son directamente insufribles. Existe una alternativa en modo texto que algunos prefieren a ncdu que es <a href="http://gt5.sourceforge.net/">gt5</a>.</p>joe di castroFri, 19 Oct 2012 22:40:00 +0200http://joedicastro.com/productividad-linux-ncdu.htmlproductividadlinuxncursestamañoProductividad & Linux: Rangerhttp://joedicastro.com/productividad-linux-ranger.html<p>Algunos pensarán, de acuerdo, podemos entender que prefieras un <a href="http://joedicastro.com/productividad-en-el-escritorio-linux-tiling.html">gestor de ventanas de mosaico</a>, o que emplees aplicaciones como <a href="http://joedicastro.com/productividad-linux-pentadactyl.html">Pentadactyl</a>, <a href="http://joedicastro.com/productividad-linux-newsbeuter.html">Newsbeuter</a>, <a href="http://joedicastro.com/productividad-linux-zathura.html">Zathura</a> o <a href="http://joedicastro.com/productividad-linux-turses.html">Turses</a>, pero <strong>Ranger</strong>... ya es demasiado. ¿A quien en su sano juicio se le ocurriría utilizar semejante engendro? A mí, y no solo lo utilizo a diario, si no que además opino que es quizás la mejor aplicación que he descubierto en el último año y medio. Y esto último es mucho decir para alguien, que como yo, está continuamente buscando formas de mejorar su modo de trabajo.</p> <p><a href="http://ranger.nongnu.org/">Ranger</a> es un administrador de archivos en modo texto. Pero no es un administrador de archivos en modo texto clásico a dos columnas, como el norton commander y similares. No, Ranger es una pequeña joya con un planteamiento distinto y tan potente, que puede conseguir que olvides que no podías vivir sin un gestor de archivos gráfico como <a href="https://es.wikipedia.org/wiki/Nautilus_(software)">Nautilus</a>, <a href="https://es.wikipedia.org/wiki/Konqueror">Konqueror</a>, <a href="https://es.wikipedia.org/wiki/Dolphin_(administrador_de_archivos)">Dolphin</a> o <a href="https://es.wikipedia.org/wiki/Thunar">Thunar</a>.</p> <h2 id="ranger">Ranger</h2> <p>Tengo que estar enormemente agradecido a su autor, <a href="https://github.com/hut">Roman Zimbelmann</a> no solo por su trabajo, si no por mostrarme que incluso en modo texto, se puede revolucionar el mundo de la usabilidad. Evidentemente, en una aplicación que basa su control en el teclado (tiene un soporte muy básico del ratón), es requisito imprescindible invertir algún tiempo en aprender a utilizarlo, ya que no es tan intuitivo como una aplicación gráfica. A menos que seas un usuario típico de <a href="https://es.wikipedia.org/wiki/Vim">Vim</a>, entonces te encontrarás como en casa. Una vez que dominas esta aplicación, el moverse entre los directorios y el realizar operaciones se hace a velocidad de vértigo y con control absoluto (siempre que no seas un manazas con el teclado).</p> <p><strong>Ranger</strong> está desarrollado en <strong>Python</strong> y emplea una interfaz ncurses igual que <a href="http://joedicastro.com/productividad-linux-turses.html">Turses</a>. Al contrario de lo que algunos puedan pensar, el estar desarrollado en Python no lo convierte ni en pesado ni en lento, si no que se mueve a velocidad endiablada y consume una cantidad de memoria ridícula comparada con cualquier gestor de archivos gráfico.</p> <p style="text-align:center;"><img src="pictures/ranger.png" width="700" height="437" alt="Ranger" /></p> <p>Aquí puede verse una imagen típica de ranger, visualizando el contenido de un directorio y previsualizando el contenido de un fichero, en este caso un fichero de código python.</p> <h3 id="caracter+sticas">Características</h3> <p>¿Qué se puede hacer con ranger?, bueno, quizás es mejor preguntarse que no se puede hacer con Ranger. Prácticamente todas las funciones a las que estés acostumbrado en un administrador de archivos gráfico se pueden realizar con Ranger. Vamos primero a ver un resumen de sus características:</p> <ul> <li>Soporte de UTF-8 por defecto</li> <li>Visualización en múltiples columnas</li> <li>Previsualización del directorio o fichero seleccionado</li> <li>Operaciones comunes sobre los ficheros. Crear, copiar, borrar, cambiar atributos (<code>chmod</code>), etc...</li> <li>Combinaciones de teclado y consola inspiradas en Vim</li> <li>Autodetección de tipos de fichero y apertura de los mismos con el programa adecuado</li> <li>Permite establecer etiquetas y marcadores sobre archivos y directorios</li> <li>Empleo de pestañas. Nos permite navegar por varios directorios simultáneamente sin necesidad de abrir otra instancia del programa. Además se pueden realizar operaciones entre ellas</li> <li>Muestra una barra de progreso para las operaciones que lo necesitan</li> </ul> <p>Conviene dejar claro que no es un programa para <em>impacientes</em>, hacerse con él y sus innumerables opciones requiere tiempo. Hay que leerse la ayuda del programa y practicar con él. A su vez, si queremos personalizar las opciones o ampliarlo, debemos comprender como funcionan sus archivos de configuración, mejor aún si tenemos conocimientos de Python. La documentación de su web, así como la de sus páginas <em>man</em> está un poco desactualizada, por lo que sacarle todo su jugo requiere algo de paciencia.</p> <h3 id="ejemplos">Ejemplos</h3> <p>Voy a intentar dar algo de visibilidad a algunas de las capacidades que nos ofrece ranger empleando una par de ejemplos que lo ilustren.</p> <p>En el siguiente ejemplo vemos la previsualización que hace ranger en función del tipo de fichero que se trate.</p> <div style="text-align:center"> <iframe src="http://player.vimeo.com/video/62061254?title=0&amp;byline=0&amp;portrait=0" width="700" height="438"> </iframe> <p>Previsualización de archivos en ranger con varios tipos de archivo. Recomiendo ver en alta resolución y a pantalla completa.</p> </div> <p>La previsualización de imágenes en ASCII puede parecer una tontería, pero resulta muy útil a la hora de diferenciar entre distintas imágenes con nombre muy parecido. El fichero en HTML está renderizado en vez de mostrarnos el texto plano, algo más amigable. También se agradece mucho el que los ficheros de código se vean con resaltado de sintaxis.</p> <blockquote> <p>Conviene aclarar que para realizar esta previsualización es necesario tener instalado una serie de pequeñas aplicaciones que se detallan en el sitio de ranger como dependencias.</p> </blockquote> <p>Aquí vemos como se abren automáticamente los programas adecuados en función del tipo de archivo (se puede configurar que aplicaciones emplear y cuales usar en cada momento)</p> <div style="text-align:center"> <iframe src="http://player.vimeo.com/video/62634892?title=0&amp;byline=0&amp;portrait=0" width="700" height="438"> </iframe> <p>Ejecución automática de aplicaciones en función del tipo de archivo. Recomiendo ver en alta resolución y a pantalla completa.</p> </div> <p>En el caso del fichero Torrent, al que no tengo asociada ninguna aplicación en ranger, me abre un comando en el que puedo especificar directamente la aplicación que deseo emplear para gestionarlo. En este caso, ninguna. En el archivo comprimido solo me muestra el contenido del mismo, podría asociarle alguna aplicación, pero ya tengo comandos para manejarlos dentro del propio ranger, algo que veremos a continuación.</p> <h2 id="mi_configuraci+n">Mi configuración</h2> <p>No he personalizado mucho mi configuración de momento, pero quien quiera echarle un vistazo puede hacerlo en mi repositorio dotfiles en <a href="http://github.com/joedicastro/dotfiles">GitHub</a></p> <h3 id="archivos_de_configuraci+n">Archivos de configuración</h3> <p>Para configurar ranger necesitamos editar ciertos archivos, que crearemos por primera vez con el siguiente comando:</p> <div class="codehilite"><pre><span class="nv">$ </span>ranger --copy-config<span class="o">=</span>all </pre></div> <p>qué nos creara los siguientes archivos por defecto en la carpeta <code>~/.config/ranger/</code>:</p> <ul> <li><code>commands.py</code> <em>(python)</em>, en este archivo se configuran los comandos a emplear en la línea de comandos de ranger</li> <li><code>options.py</code> <em>(python)</em>, el fichero de opciones principal de ranger</li> <li><code>rc.conf</code> <em>(texto)</em>, aquí configuramos los atajos de teclado de ranger</li> <li><code>rifle.conf</code> <em>(texto)</em>, para establecer los programas que ejecutaran o abrirán un tipo de archivo en orden de preferencia</li> <li><code>scope.sh</code> <em>(bash)</em>, los programas empleados para previsualizar un determinado tipo de archivo</li> </ul> <p>Adicionalmente, con el uso se añadirán tres ficheros más: <code>bookmarks</code>, <code>history</code> y <code>tagged</code> que guardarán los marcadores, la historia de comandos y las etiquetas respectivamente.</p> <h3 id="gestionar_la_papelera">Gestionar la papelera</h3> <p>Por defecto ranger no contempla la gestión de la papelera de Linux que implementan escritorios como Gnome. Aunque no empleo ningún entorno de escritorio ni gestores de archivos gráficos, si me interesa gestionar la papelera, pues cada vez más aplicaciones la emplean para eliminar los archivos. De hecho en <em>bash</em> y <em>zsh</em> tengo un alias para <code>rm</code> que mueve los archivos a la papelera en vez de eliminarlos.</p> <div class="codehilite"><pre><span class="nb">alias </span><span class="nv">rm</span><span class="o">=</span><span class="s1">&#39;mv --target-directory ~/.local/share/Trash/files&#39;</span> </pre></div> <p>Para gestionar la papelera desde ranger, añado dos atajos de teclado y un comando editando varios archivos de configuración de la siguiente manera:</p> <p><strong>Mandar archivos a la papelera</strong></p> <p>Para mandar a la papelera lo que tengamos seleccionado actualmente, en lugar de eliminarlo directamente, añadimos esta línea al fichero <code>rc.conf</code></p> <div class="codehilite"><pre><span class="c"># move to trash</span> <span class="nb">map</span> <span class="n">DD</span> <span class="n">shell</span> <span class="n">mv</span> <span class="o">-</span><span class="n">t</span> <span class="o">~/.</span><span class="n">local</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">Trash</span><span class="o">/</span><span class="n">files</span> <span class="o">%</span><span class="n">s</span> </pre></div> <p>de este modo, cada vez que pulsemos <strong><code>DD</code></strong> el contenido seleccionado es movido al directorio donde tenemos nuestra papelera.</p> <p><strong>Movernos a la papelera</strong></p> <p>Del mismo modo que ranger provee por defecto de atajos de teclado para movernos al directorio <code>home</code>, al directorio raiz, etc, he añadido un atajo de teclado siguiendo el mismo criterio para acceder a nuestra papelera. Añadimos lo siguiente al fichero <code>rc.conf</code></p> <div class="codehilite"><pre><span class="c"># go to trash</span> <span class="nb">map</span> <span class="n">gp</span> <span class="n">cd</span> <span class="o">~/.</span><span class="n">local</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">Trash</span><span class="o">/</span><span class="n">files</span> </pre></div> <p>así, pulsando <strong><code>gp</code></strong> vamos directamente a la papelera, estemos donde estemos.</p> <p><strong>Vaciar la papelera</strong></p> <p>Para vaciar la papelera opto por emplear un comando, para ello tenemos que editar otro fichero, <code>commands.py</code>, y añadir lo siguiente</p> <div class="codehilite"><pre><span class="k">class</span> <span class="nc">empty</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;</span> <span class="sd"> :empty</span> <span class="sd"> Empties the trash directory ~/.local/share/Trash/files</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s">&quot;rm -rf ~/.local/share/Trash/files/{*,.[^.]*}&quot;</span><span class="p">)</span> </pre></div> <p>por lo que vaciar la papelera se convierte en algo tan simple como teclear <strong><code>:empty</code></strong> o para los más cómodos <strong><code>:em↹</code></strong></p> <h3 id="desmontar_una_unidad_con_udiskie">Desmontar una unidad con udiskie</h3> <p>Dada mi "particular" configuración, ya que no empleo ningún escritorio, empleo la herramienta <a href="https://bitbucket.org/byronclark/udiskie">udiskie</a> para automontar unidades de almacenamiento externas, como unidades USB o tarjetas de memoria. El montado se hace de forma automática y solo el desmontado ha de hacerse de forma manual. Ya que no quiero teclear el comando cada vez que desee desmontar una unidad, lo que hago es hacerlo desde ranger. En el fichero <code>rc.conf</code> mapeamos este atajo</p> <div class="codehilite"><pre><span class="c"># umount a drive with udiskie</span> <span class="nb">map</span> <span class="n">un</span> <span class="n">shell</span> <span class="o">-</span><span class="n">d</span> <span class="n">udiskie</span><span class="o">-</span><span class="n">umount</span> <span class="o">%</span><span class="n">d</span><span class="o">/%</span><span class="n">f</span> </pre></div> <p>así para desmontar una unidad inicio ranger (en mi caso <strong><code>Win + F1</code></strong>), me dirijo a las unidades externas montadas, <strong><code>gm</code></strong>, selecciono la unidad deseada y la desmonto, <strong><code>un</code></strong>. Un proceso que me lleva apenas dos segundos, sin abandonar las manos del teclado, compárese con hacerlo con un ratón y un entorno gráfico.</p> <h3 id="expulsar_un_cddvd">Expulsar un CD/DVD</h3> <p>Del mismo modo, en lugar de abrir un terminal y escribir el comando <code>eject</code>, en determinadas circunstancias, por ejemplo al acabar de examinar el contenido de un disco, prefiero hacerlo directamente desde ranger. Para ello en el fichero <code>rc.conf</code> creamos este atajo de teclado</p> <div class="codehilite"><pre><span class="c"># eject a CD-ROM/DVD</span> <span class="nb">map</span> <span class="n">ej</span> <span class="n">shell</span> <span class="o">-</span><span class="n">d</span> <span class="n">eject</span> </pre></div> <h3 id="trabajar_con_archivos_comprimidos">Trabajar con archivos comprimidos</h3> <p>Estos comandos los he sacado de el <a href="https://wiki.archlinux.org/index.php/Ranger">Wiki de Arch Linux</a> y los he adaptado a la versión de ranger que estoy empleando en este momento, la 1.5.5</p> <p><strong>Extraer los ficheros de un archivo comprimido</strong></p> <p>Con el comando <strong><code>:extracthere</code></strong> extraemos el contenido de un archivo/s comprimido que previamente habremos seleccionado para copia (es decir empleando el atajo <strong><code>yy</code></strong>). El contenido se extrae en el directorio en el que nos encontremos actualmente. Es muy comodo para extraer múltiples archivos comprimidos a la vez, si quisieramos descomprimir solo un archivo y en el mismo directorio en el que este se encuentra, podríamos emplear el atajo <strong><code>1l</code></strong></p> <p>Para añadir el comando a ranger, tenemos que insertar esta clase en el fichero <code>commands.py</code></p> <div class="codehilite"><pre><span class="k">class</span> <span class="nc">extracthere</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span> <span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot; Extract copied files to current directory &quot;&quot;&quot;</span> <span class="n">copied_files</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">copy</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">copied_files</span><span class="p">:</span> <span class="k">return</span> <span class="k">def</span> <span class="nf">refresh</span><span class="p">(</span><span class="n">_</span><span class="p">):</span> <span class="n">cwd</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">get_directory</span><span class="p">(</span><span class="n">original_path</span><span class="p">)</span> <span class="n">cwd</span><span class="o">.</span><span class="n">load_content</span><span class="p">()</span> <span class="n">one_file</span> <span class="o">=</span> <span class="n">copied_files</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="n">cwd</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">thisdir</span> <span class="n">original_path</span> <span class="o">=</span> <span class="n">cwd</span><span class="o">.</span><span class="n">path</span> <span class="n">au_flags</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;-X&#39;</span><span class="p">,</span> <span class="n">cwd</span><span class="o">.</span><span class="n">path</span><span class="p">]</span> <span class="n">au_flags</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">1</span><span class="p">:]</span> <span class="n">au_flags</span> <span class="o">+=</span> <span class="p">[</span><span class="s">&#39;-e&#39;</span><span class="p">]</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">copy</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">cut</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">copied_files</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span> <span class="n">descr</span> <span class="o">=</span> <span class="s">&quot;extracting: &quot;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">one_file</span><span class="o">.</span><span class="n">path</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">descr</span> <span class="o">=</span> <span class="s">&quot;extracting files from: &quot;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">one_file</span><span class="o">.</span><span class="n">dirname</span><span class="p">)</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">CommandLoader</span><span class="p">(</span><span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="s">&#39;aunpack&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="n">au_flags</span> \ <span class="o">+</span> <span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">path</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">copied_files</span><span class="p">],</span> <span class="n">descr</span><span class="o">=</span><span class="n">descr</span><span class="p">)</span> <span class="n">obj</span><span class="o">.</span><span class="n">signal_bind</span><span class="p">(</span><span class="s">&#39;after&#39;</span><span class="p">,</span> <span class="n">refresh</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">loader</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> </pre></div> <p><strong>Crear un archivo comprimido</strong></p> <p>Este comando te permite seleccionar uno o varios ficheros y crear un archivo comprimido al llamar al comando <strong><code>:compress</code></strong>. Este comando te permite (a través del autocompletado) darle un nombre automático a partir del directorio o uno personalizado. Te permite además seleccionar el tipo de compresión en función de la extension empleada.</p> <p>En el fichero <code>commands.py</code> añadimos el siguiente código.</p> <div class="codehilite"><pre><span class="k">class</span> <span class="nc">compress</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span> <span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot; Compress marked files to current directory &quot;&quot;&quot;</span> <span class="n">cwd</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">thisdir</span> <span class="n">marked_files</span> <span class="o">=</span> <span class="n">cwd</span><span class="o">.</span><span class="n">get_selection</span><span class="p">()</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">marked_files</span><span class="p">:</span> <span class="k">return</span> <span class="k">def</span> <span class="nf">refresh</span><span class="p">(</span><span class="n">_</span><span class="p">):</span> <span class="n">cwd</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">get_directory</span><span class="p">(</span><span class="n">original_path</span><span class="p">)</span> <span class="n">cwd</span><span class="o">.</span><span class="n">load_content</span><span class="p">()</span> <span class="n">original_path</span> <span class="o">=</span> <span class="n">cwd</span><span class="o">.</span><span class="n">path</span> <span class="n">parts</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="p">()</span> <span class="n">au_flags</span> <span class="o">=</span> <span class="n">parts</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="n">descr</span> <span class="o">=</span> <span class="s">&quot;compressing files in: &quot;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">parts</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">CommandLoader</span><span class="p">(</span><span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="s">&#39;apack&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="n">au_flags</span> <span class="o">+</span> \ <span class="p">[</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">relpath</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">path</span><span class="p">,</span> <span class="n">cwd</span><span class="o">.</span><span class="n">path</span><span class="p">)</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">marked_files</span><span class="p">],</span> <span class="n">descr</span><span class="o">=</span><span class="n">descr</span><span class="p">)</span> <span class="n">obj</span><span class="o">.</span><span class="n">signal_bind</span><span class="p">(</span><span class="s">&#39;after&#39;</span><span class="p">,</span> <span class="n">refresh</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">loader</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="k">def</span> <span class="nf">tab</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot; Complete with current folder name &quot;&quot;&quot;</span> <span class="n">extension</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;.zip&#39;</span><span class="p">,</span> <span class="s">&#39;.tar.gz&#39;</span><span class="p">,</span> <span class="s">&#39;.rar&#39;</span><span class="p">,</span> <span class="s">&#39;.7z&#39;</span><span class="p">]</span> <span class="k">return</span> <span class="p">[</span><span class="s">&#39;compress &#39;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fm</span><span class="o">.</span><span class="n">thisdir</span><span class="o">.</span><span class="n">path</span><span class="p">)</span> <span class="o">+</span> <span class="n">ext</span> <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="n">extension</span><span class="p">]</span> </pre></div>joe di castroThu, 18 Oct 2012 21:50:00 +0200http://joedicastro.com/productividad-linux-ranger.htmlproductividadlinuxpythonncursesProductividad & Linux: Turseshttp://joedicastro.com/productividad-linux-turses.html<p>Que medio mundo parece estar conectado a <a href="http://twitter.com">Twitter</a> no es ninguna novedad. Y que si sigues a un buen número de personas, el intentar estar al tanto de todo lo que ocurre es una temeridad, tampoco debería sorprender a nadie. De hecho, dado su éxito y el enorme flujo de información que circula por él, se han desarrollado cientos de herramientas para gestionarlo.</p> <p>Desde que cree mi cuenta en twitter, he probado unas cuantas, unas veinte (y solo en Linux, en el resto uso la web). La primera, y la elección más obvia ya que por aquel entonces usaba Ubuntu, fue <strong>Gwibber</strong> . Luego cansado de sus muchos problemas, probé un sinnúmero de aplicaciones, solo merece la pena reseñar una: <a href="http://hotot.org/">Hotot</a>. Es la mejor aplicación gráfica para twitter en Linux que conozco.</p> <p>Pero guiado por el mismo objetivo de <a href="http://joedicastro.com/tag/productividad.html">mejorar la productividad</a> en mis herramientas habituales de trabajo, me lancé a la búsqueda de un cliente de twitter que encajara en la misma filosofía. No hay muchas alternativas, la mayoría, hay que reconocerlo, son demasiado "crudas" incluso para mí, que soy un amante de la consola. Pero entonces dí con una pequeña joya, <a href="http://tyrs.nicosphere.net/">Tyrs</a>, desarrollada por <a href="https://github.com/Nic0">Nicolas Paris</a>. Era una herramienta sencilla, pero que cumplía muy bien con todo lo que buscaba de ella. Pero un buen día, Nicolas, en su afán por mejorarla, empezó a reescribir la herramienta empleando una nueva librería para gestionar el interfaz. Las primeras versiones tenían varios fallos y Nicolas pronto se vio desbordado por una tarea que no le apetecía continuar y a la que no podía dedicar más tiempo. Y <a href="http://www.nicosphere.net/small-projects-life-depends-on-his-owner/">decidió abandonar el proyecto</a>, con la esperanza de que alguien se atreviera a retomarlo. Cuando leí la entrada de su blog no perdí la esperanza del todo, al fin y al cabo, estaba desarrollado en Python, un lenguaje con el que me desenvuelvo. Mientras esperaba que hacer, seguí usando la última versión estable a diario. Pero entonces, apareció el milagro, <strong>Turses</strong></p> <h2 id="turses">Turses</h2> <p><a href="https://github.com/alejandrogomez/">Alejandro Gómez</a>, un usuario de <strong>Tyrs</strong> <a href="http://dialelo.com/Python/turses/2012/03/02/turses-un-cliente-de-twitter-con-interfaz-ncurses.html">se lanzó</a> a crear su propia aplicación basándose en él. Y no solo garantizaba la continuidad del buen trabajo empezado por Nicolas, si no que llegaba lleno de ideas frescas y muchas ganas de hacerlo bien. El propio Nicolas <a href="http://www.nicosphere.net/turses-a-fork-from-tyrs-ncurses-twitter-client/">le felicitó</a> por el trabajo y la iniciativa. A día de hoy, el proyecto se sigue desarrollando, y aunque aún tiene algunas metas marcadas por delante, la aplicación es perfectamente usable en el día a día, de hecho es mi cliente habitual.</p> <p>Como ya se habrá podido deducir, <a href="https://github.com/alejandrogomez/Turses">Turses</a> es un cliente de twitter para la consola con interfaz <a href="https://es.wikipedia.org/wiki/Ncurses">ncurses</a>. Está desarrollado en Python y emplea la librería <a href="http://excess.org/urwid/">Urwid</a> para crear la interfaz en curses. Lo mejor de esta aplicación es que emplea atajos de teclado inspirados en <strong>Vim</strong> y es totalmente controlable desde el teclado. Esto unido a que emplea una interfaz basada en texto, la convierten en la aplicación más ágil de todas las que haya probado. <strong>Hotot</strong> también tiene algunas combinaciones de teclas muy útiles, pero ni se acercan a lo que <strong>Turses</strong> te permite.</p> <p>Aquí se puede ver el aspecto por defecto de Turses</p> <p style="text-align:center;"><img src="pictures/turses.png" width="700" height="290" alt="Turses" /></p> <p>Pero no se acaban ahí las bondades de Turses, tiene algunas características geniales como la gestión dinámica de bufferes (líneas temporales) y de columnas. Demos un repaso a lo que nos permite la aplicación:</p> <ul> <li><strong>Múltiples líneas temporales</strong> (<em>bufferes</em>). Es decir, nos permite consultar los tweets de la gente a la que seguimos, los nuestros, menciones, etc. Es decir, los bufferes habituales, incluidos conversaciones, búsquedas y hashtags. Y podemos tenerlas simultáneamente abiertas y navegar entre ellas muy fácilmente.</li> <li><strong>Múltiples columnas</strong>. En cada columna se sitúa un buffer, y podemos añadir o quitar columnas a voluntad de forma muy sencilla. Es decir, que podemos visualizar un solo buffer de forma predefinida, o podemos ver varios a la vez distribuidos en múltiples columnas.</li> <li><strong>Tweet, Reply, Retweet, Borrar</strong>. Vamos, que permite las operaciones habituales con los tweets. Además se puede hacer un Retweet editando el texto, algo que parece obvio, pero que en algunas aplicaciones no es tan sencillo.</li> <li><strong>Seguir/dejar de seguir</strong> a un usuario. Podemos hacerlo bien a través de un tweet o bien introduciendo el nombre del usuario.</li> <li><strong>Des/Marcar como favorito</strong>.</li> <li><strong>Enviar mensajes directos</strong>.</li> <li><strong>Abrir URLs en un navegador</strong>. Nos permite abrir las direcciones que aparecen en un tweet, así como abrir el propio tweet.</li> <li><strong>Visualizar conversaciones</strong>. Podemos abrir un nuevo buffer con la conversación relacionada con un tweet.</li> <li><strong>Contador de los no leídos</strong> funciona para todos los bufferes y nos permite ponerlo a cero manualmente cuando queremos ignorar algunos no leídos.</li> <li><strong>Búsqueda</strong>. Se puede buscar tanto por usuario como por termino.</li> <li><strong>Ver los tweets de cualquier usuario </strong>.</li> <li><strong>Visualizar el perfil de un usuario</strong>.</li> <li><strong>Totalmente personalizable</strong> y la configuración se guarda en un fichero de texto plano.</li> <li><strong>Múltiples cuentas</strong>, eso sí, una por ejecución.</li> <li><strong>Ayuda en línea</strong> con todas las combinaciones de teclas posibles. Accesible a través de la tecla <strong><code>?</code></strong></li> </ul> <p>Interfaz de Turses mostrando múltiples columnas</p> <p style="text-align:center;"><img src="pictures/turses_2cols.png" width="700" height="285" alt="Turses con multiples columnas" /></p> <p>Y entre las metas que tiene marcadas su autor, nos encontramos con el soporte para listas, streaming, notificaciones emergentes y múltiples sesiones. Estoy seguro de que las acabará incorporando, le sobra capacidad. Aunque he de reseñar que actualmente he contribuido con una porción de código minúscula al proyecto y que tengo la intención de seguir colaborando en todo lo que pueda. Si eres programador Python y te apetece echar una mano, <a href="https://github.com/alejandrogomez/Turses">anímate</a>, Alejandro es muy receptivo y un tío muy majo que estará encantado con toda la ayuda que le podamos dar.</p> <h2 id="mi_configuraci+n">Mi configuración</h2> <p>Si a alguien le puede servir como inspiración mi configuración, esta disponible en <a href="http://github.com/joedicastro/dotfiles">GitHub</a></p> <p>Turses mostrando la información del perfil del autor de un tweet</p> <p style="text-align:center;"><img src="pictures/turses_uinfo.png" width="700" height="429" alt="Turses mostrando la información de un usuario" /></p> <h2 id="alternativas">Alternativas</h2> <p>Solo conozco dos alternativas en la misma línea que merezca la pena reseñar, las demás que he probado no estaban a la altura:</p> <ul> <li> <p><a href="http://www.vim.org/scripts/script.php?script_id=2204">TwitVim</a>, es un plugin para Vim. Funciona fantásticamente bien, eso sí, solo apropiado para usuarios de Vim. La probé un tiempo y me gusto, pero personalmente no me gusta emplear Vim para esta tarea y Turses es bastante más manejable.</p> </li> <li> <p><a href="http://www.floodgap.com/software/ttytter/">TTYtter</a>, está escrito en Perl y no tiene interfaz. Trabaja en la línea de comandos a modo de interprete. Funciona muy bien y también lo usé un tiempo, pero su propio funcionamiento le reste eficiencia comparado con Turses.</p> </li> </ul>joe di castroThu, 21 Jun 2012 22:50:00 +0200http://joedicastro.com/productividad-linux-turses.htmlproductividadlinuxncursespythontwitterProductividad & Linux: Newsbeuterhttp://joedicastro.com/productividad-linux-newsbeuter.html<p>Uno de los pilares de la productividad es, como no, la gestión del tiempo. Otro de los pilares fundamentales es, inexorablemente, el conocimiento. Si pierdes el tiempo en tareas irrelevantes (o directamente procrastinando), tu productividad se resiente irremediablemente. Si no tiene los conocimientos adecuados y suficientes, consumes el tiempo aprendiendo a hacerlo o directamente lo pierdes haciéndolo mal. Hoy en día, rara es la actividad donde la formación continua no sea un requisito indispensable, no ya para mejorar o mantener tu rendimiento, si no simplemente para poder seguir ejerciéndola.</p> <p>Por lo tanto nos vemos condenados a intentar mantenernos al día (y ampliar conocimientos), mientras que procuramos dedicarle el menor tiempo posible para no menoscabar nuestro rendimiento. Tal delicado equilibrio no es poca hazaña en nuestros días. Nos vemos inundados de tal cantidad de información, que el filtrado es la única manera de intentar sobrevivir a esa enorme vorágine de datos a la que nos enfrentamos. Afortunadamente tenemos herramientas. Desde hace muchos años he confiado esta tarea a emplear fuentes <strong>RSS</strong> de calidad y una buena herramienta para gestionarlas.</p> <h2 id="mi_b+squeda_del_cliente_rss_ideal">Mi búsqueda del cliente RSS ideal</h2> <p>He empleado muchas herramientas distintas para esta tarea, siempre intentando tener la más idónea para filtrar muchas fuentes RSS en el menor tiempo posible, sin pasar por alto lo que me interesa conocer. Algunas muy buenas, que usaba cuando aún empleaba Windows como SO principal, ya no existen. En Linux he pasado por las más conocidas (en orden cronológico):</p> <ul> <li> <p><a href="http://liferea.sourceforge.net/">Liferea</a>, era muy buena cuando la deje, lo de mostrar los comentarios en las entradas es algo que no he vuelto a ver en ninguna otra herramienta. Pero después de varios años de uso, la abandoné cuando se había convertido en insufriblemente lenta.</p> </li> <li> <p><a href="http://userbase.kde.org/Akregator">Akregator</a>, no era para mí, nunca acabe encontrándome a gusto con ella. Lo hacía todo medianamente bien, pero no destacaba en nada, pronto la abandoné.</p> </li> <li> <p><a href="http://www.blogbridge.com/">Blogbride</a>, su planteamiento es diferente al resto. Es una buena aplicación y estuve con ella muchos meses. Pero siempre seguí buscando algo más eficiente.</p> </li> <li> <p><a href="http://www.rssowl.org/">RSSOwl</a>, la mejor aplicación para leer RSS para escritorio que he conocido. La he usado durante años. Está construida sobre Eclipse. Ofrece muchas posibilidades de personalización y filtrado. Es muy rápida, pero debido a que depende de Eclipse y java, si manejas un número considerable de fuentes (+1000 en aquella época), se puede volver un poco pesada. Además, si como yo, dejabas muchos artículos para leer en otro momento, la base de datos crecía de tal manera, que podía llegar a ser muy lenta. La abandoné buscando algo aún más ágil y productivo.</p> </li> <li> <p><a href="https://es.wikipedia.org/wiki/Google_Reader">Google Reader</a>, decidí darle una oportunidad. Por aquella época había empezado a usar Read it Later (hoy <a href="http://getpocket.com">Pocket</a>) para guardar aquello que quería leer en otro momento o con más calma. La integración con RIL me obligaba a abandonar el teclado y usar el ratón. Además el rediseño que hizo Google no me convencía. Decidí buscar algo aún más rápido y eficiente.</p> </li> </ul> <p>Durante todo ese tiempo probé muchísimas otras alternativas (incluidos complementos para navegadores web) y no encontraba nada que me valiese. Es muy difícil encontrar una aplicación de este tipo que te permita manejar un gran número de fuentes RSS de forma realmente eficiente. Al final ya estaba decidido a regresar a RSSOwl. Pero acostumbrado a <a href="http://joedicastro.com/productividad-linux-pentadactyl.html">Pentadactyl</a> y Vim y las aplicaciones <a href="https://es.wikipedia.org/wiki/Ncurses">ncurses</a>, decidí buscar algo en esa línea, y lo encontré.</p> <h2 id="newsbeuter">Newsbeuter</h2> <p><a href="http://www.newsbeuter.org/">Newsbeuter</a> es un juego de palabras con la palabra alemana "Wildbeuter" que significa <a href="https://es.wikipedia.org/wiki/Cazador_recolector">cazador-recolector</a>, por lo que Newsbeuter vendría a ser algo así como <em>Cazador/Recolector de Noticias</em>. Newsbeuter es una aplicación para leer fuentes RSS y Atom que utiliza una interfaz tipo ncurses para consola. Quién esté familiarizado con el cliente de correo <a href="https://es.wikipedia.org/wiki/Mutt">Mutt</a> se sentirá cómodo enseguida, ya que se inspira en este. Está programado en C++ y dado que funciona en modo texto, una de sus ventajas es la enorme agilidad que proporciona para moverse entre fuentes y noticias.</p> <p>Un resumen de sus características:</p> <ul> <li>Permite suscribirnos a fuentes RSS y Atom</li> <li>Soporta <a href="https://es.wikipedia.org/wiki/OPML">OPML</a> tanto para importar como para exportar las subscripciones</li> <li>Descarga de podcasts</li> <li>Se pueden configurar todos los atajos de teclado libremente</li> <li>Podemos realizar búsquedas entre todos los artículos descargados. Similar a Vim</li> <li>Es posible crear etiquetas para dividir nuestras subscripciones en categorías y realizar filtrados y búsquedas en función a ellas</li> <li>Se pueden sincronizar las fuentes con Google Reader y <a href="http://tt-rss.org/redmine/">Tiny Tiny RSS</a></li> <li>Podemos configurar el color y las cadenas de texto para personalizar su aspecto</li> <li>Se pueden eliminar de forma automática artículos que no deseemos a través de un <a href="https://en.wikipedia.org/wiki/Kill_file">"killfile"</a></li> <li>Es posible integrar cualquier fuente de datos a través de un flexible sistema de filtros y plugins: Fichero con urls, fichero OPML, fichero OPML online, Google Reader, varios ficheros...</li> <li>Se pueden crear "meta fuentes" empleando un potente lenguaje de consultas</li> <li>Permite crear marcadores a partir de cualquier enlace del articulo empleando una aplicación externa o un script</li> <li>Permite guardar artículos en texto plano</li> <li>Podemos otorgar etiquetas de un solo carácter que el autor denomina "flags" por articulo y varias por articulo. Útiles para emplearlas conjuntamente con los filtros</li> <li>Se pueden definir macros</li> <li>Linea de comandos para poder ejecutar comandos y cambiar opciones sobre la marcha</li> <li>Funciona en Linux, Mac OS y FreeBSD</li> <li>Programado en C++ y guarda los artículos en una BDD <a href="http://sqlite.org/">SQLite</a></li> <li><a href="http://newsbeuter.org/doc/newsbeuter.html">Documentación</a> bastante completa</li> </ul> <p>Pantalla con la configuración por defecto de Newsbeuter</p> <p style="text-align:center;"><img src="pictures/newsbeuter_default.png" width="700" height="410" alt="Newsbeuter" /></p> <h2 id="lo_que_lo_distingue">Lo que lo distingue</h2> <p>Muchas de estas características las comparte con otras aplicaciones de las mencionadas antes, pero lo que realmente distingue a Newsbeuter de todas ellas es lo siguiente:</p> <ul> <li>Totalmente controlable desde el teclado, lo que unido a su velocidad, le proporciona una agilidad inigualable.</li> <li>Basado en texto, lo que nos evita distraernos de lo importante, el contenido.</li> <li>Consumo ridículo de memoria y recursos comparado con cualquiera aplicación mencionada antes. En el peor de los casos, me ha consumido unos 30 MiB de RAM (para la versión de 64 bits)</li> <li>Se puede configurar el números de hilos de proceso para descargar noticias. En mi caso, con 8 hilos, tarda unos 40s en leer unos 250 canales RSS. Solo Google Reader por su funcionamiento, puede mejorar esto.</li> <li>Configurable con un fichero de texto plano</li> </ul> <p>Como dijo <a href="http://www.zedshaw.com/essays/i_want_the_mutt_of_feed_readers.html">Zed Shaw</a> y refrenda el autor de la aplicación, <a href="http://synflood.at/">Andreas Krennmair</a>,</p> <blockquote> <p>"Newsbeuter es el Mutt de los lectores de noticias RSS"</p> </blockquote> <p>Desde mi propia experiencia puedo decir que este programa ha cambiado mi forma de leer las <em>noticias del día</em>. Antes, para mi, era muy importante que el lector de noticias que empleara, utilizara un estilo homogéneo entre todas las fuentes y artículos, con el fin de centrarme en el contenido y no perder el tiempo con nimiedades. Es algo más importante de lo que pueda parecer a simple vista, cuando quieres emplear el menor tiempo posible en adquirir la información y al mismo tiempo quieres asimilar lo que lees. Si cuando vas a leer las noticias tienes 45 minutos y 300 artículos sin leer, el cambiar de un articulo con fondo negro y letra Sans Serif mediana a uno con fondo blanco y letra Serif enorme, te supone una distracción y una adaptación de la vista innecesarias e incomodas.</p> <p>Vista de un articulo con mi configuración</p> <p style="text-align:center;"><img src="pictures/newsbeuter_articulo.png" width="700" height="843" alt="Articulo en Newsbeuter" /></p> <p>Pero al comenzar a emplear Newsbeuter me di enseguida cuenta de algo, el carecer por completo de imágenes y compartir cabecera entre todos los artículos, me ha servido para pasar por alto o leer en diagonal aquello que menos me interesa. No solo filtro más rápido, si no que lo hago más eficientemente. Evidentemente hay artículos en los que las imágenes complementan necesariamente al articulo. En estos casos o bien la abro directamente en el navegador (tan sencillo como pulsar <strong><code>o</code></strong> ) o bien puedo abrir las imágenes de forma independiente en el mismo si me interesa por ejemplo ver solo una. En este sentido, Newsbeuter proporciona una lista de todas las Urls presentes en el articulo en forma de lista al final del mismo, pudiendo abrir cualquiera de ellas introduciendo el indice de la misma. De hecho, empleando el comando <strong><code>u</code></strong> podemos acceder a la lista completa de las mimas en una nueva ventana.</p> <h2 id="mi_configuraci+n">Mi configuración</h2> <p>Mi configuración no tiene demasiado de especial, quizás que emplea una combinación de colores distinta a la habitual y que empleo un par de scripts para las notificaciones y para crear marcadores. Esta se puede encontrar en mi repositorio de mis <em>dotfiles</em> en <a href="http://github.com/joedicastro/dotfiles">GitHub</a></p> <h2 id="notificaciones">Notificaciones</h2> <p>Para las notificaciones que emite Newsbeuter después de refrescar las noticias empleo el script <code>notify.py</code> que comentaba en este <a href="http://joedicastro.com/notificaciones-de-escritorio-en-ubuntu-desde-python.html">articulo</a> ligeramente modificado para trabajar con Newsbeuter. En la imagen se puede ver una notificación del programa.</p> <p style="text-align:center;"><img src="pictures/newsbeuter_notify.png" width="487" height="68" alt="Notificación de Newsbeuter" /></p> <div class="codehilite"><pre><span class="k">try</span><span class="p">:</span> <span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">gtk</span> <span class="kn">import</span> <span class="nn">pynotify</span> <span class="kn">import</span> <span class="nn">textwrap</span> <span class="n">NOT_NOTIFY</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span> <span class="n">NOT_NOTIFY</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">def</span> <span class="nf">notify</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="n">icon</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">wrap</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Send notification icon messages through libnotify.</span> <span class="sd"> Parameters:</span> <span class="sd"> (str) title -- The notification title</span> <span class="sd"> (str) msg -- The message to display into notification</span> <span class="sd"> (str / uri) icon -- Type of icon (ok|info|error|warm|ask|sync) or icon file</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">if</span> <span class="n">NOT_NOTIFY</span><span class="p">:</span> <span class="k">return</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">pynotify</span><span class="o">.</span><span class="n">is_initted</span><span class="p">():</span> <span class="n">pynotify</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="n">title</span><span class="p">)</span> <span class="n">gtk_icon</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;ok&#39;</span><span class="p">:</span> <span class="n">gtk</span><span class="o">.</span><span class="n">STOCK_YES</span><span class="p">,</span> <span class="s">&#39;info&#39;</span><span class="p">:</span> <span class="n">gtk</span><span class="o">.</span><span class="n">STOCK_DIALOG_INFO</span><span class="p">,</span> <span class="s">&#39;error&#39;</span><span class="p">:</span> <span class="n">gtk</span><span class="o">.</span><span class="n">STOCK_DIALOG_ERROR</span><span class="p">,</span> <span class="s">&#39;warm&#39;</span><span class="p">:</span> <span class="n">gtk</span><span class="o">.</span><span class="n">STOCK_DIALOG_WARNING</span><span class="p">,</span> <span class="s">&#39;ask&#39;</span><span class="p">:</span> <span class="n">gtk</span><span class="o">.</span><span class="n">STOCK_DIALOG_QUESTION</span><span class="p">,</span> <span class="s">&#39;sync&#39;</span><span class="p">:</span> <span class="n">gtk</span><span class="o">.</span><span class="n">STOCK_JUMP_TO</span><span class="p">}</span> <span class="k">if</span> <span class="n">wrap</span><span class="p">:</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">textwrap</span><span class="o">.</span><span class="n">wrap</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">wrap</span><span class="p">))</span> <span class="k">try</span><span class="p">:</span> <span class="n">note</span> <span class="o">=</span> <span class="n">pynotify</span><span class="o">.</span><span class="n">Notification</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span> <span class="n">helper</span> <span class="o">=</span> <span class="n">gtk</span><span class="o">.</span><span class="n">Button</span><span class="p">()</span> <span class="n">gtk_icon</span> <span class="o">=</span> <span class="n">helper</span><span class="o">.</span><span class="n">render_icon</span><span class="p">(</span><span class="n">gtk_icon</span><span class="p">[</span><span class="n">icon</span><span class="p">],</span> <span class="n">gtk</span><span class="o">.</span><span class="n">ICON_SIZE_BUTTON</span><span class="p">)</span> <span class="n">note</span><span class="o">.</span><span class="n">set_icon_from_pixbuf</span><span class="p">(</span><span class="n">gtk_icon</span><span class="p">)</span> <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span> <span class="n">note</span> <span class="o">=</span> <span class="n">pynotify</span><span class="o">.</span><span class="n">Notification</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="n">icon</span><span class="p">)</span> <span class="n">note</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Main section&quot;&quot;&quot;</span> <span class="n">notify</span><span class="p">(</span><span class="s">&#39;Newsbeuter&#39;</span><span class="p">,</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s">&#39;/home/joedicastro/.newsbeuter/icon.png&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span> <span class="n">main</span><span class="p">()</span> </pre></div> <h2 id="integraci+n_con_pocket">Integración con Pocket</h2> <p>Utilizo <a href="http://getpocket.com">Pocket</a> como nexo de unión entre el navegador y el Newsbeuter para archivar todos aquello artículos que me interesa leer, pero que quiero dejar para otro momento más idóneo. Hubo un tiempo en que empleaba <a href="http://delicious.com/">Delicious</a> para esta tarea, pero me parece más adecuado Pocket.</p> <p>Esto lo consigo empleando el comando para crear marcadores de Newsbeuter y un script en Python creado para ello. Esta es la parte del archivo de configuración que relaciona el comando con el script:</p> <div class="codehilite"><pre><span class="n">bookmark</span><span class="o">-</span><span class="n">cmd</span> &quot;<span class="o">~/</span><span class="p">.</span><span class="n">newsbeuter</span><span class="o">/</span><span class="n">send2ril</span><span class="p">.</span><span class="n">py</span>&quot; </pre></div> <p>El script hace uso de la <a href="https://bitbucket.org/Surgo/ril/src">API Python</a> para Read it Later (como se llamaba anteriormente Pocket) para guardar la url del articulo en mi cuenta de Pocket. Así pulsando <strong><code>Ctrl + b</code></strong> se guarda el marcador en Pocket.</p> <div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span> <span class="c"># -*- coding: utf8 -*-</span> <span class="sd">&quot;&quot;&quot;</span> <span class="sd"> send2ril.py: Send a new url to Read it Later</span> <span class="sd">&quot;&quot;&quot;</span> <span class="n">__author__</span> <span class="o">=</span> <span class="s">&quot;joe di castro &lt;joe@joedicastro.com&gt;&quot;</span> <span class="n">__license__</span> <span class="o">=</span> <span class="s">&quot;GNU General Public License version 3&quot;</span> <span class="n">__date__</span> <span class="o">=</span> <span class="s">&quot;18/06/2012&quot;</span> <span class="n">__version__</span> <span class="o">=</span> <span class="s">&quot;0.1&quot;</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">readitlater</span> <span class="kn">import</span> <span class="nn">ril_config</span> <span class="kn">as</span> <span class="nn">config</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Main section&quot;&quot;&quot;</span> <span class="n">api</span> <span class="o">=</span> <span class="n">readitlater</span><span class="o">.</span><span class="n">API</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">RIL_APIKEY</span><span class="p">,</span> <span class="n">config</span><span class="o">.</span><span class="n">RIL_USERNAME</span><span class="p">,</span> <span class="n">config</span><span class="o">.</span><span class="n">RIL_PASSWORD</span><span class="p">)</span> <span class="n">new</span> <span class="o">=</span> <span class="p">[{</span><span class="s">&quot;url&quot;</span><span class="p">:</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s">&quot;title&quot;</span><span class="p">:</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]}]</span> <span class="n">api</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">new</span><span class="o">=</span><span class="n">new</span><span class="p">)</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span> <span class="n">main</span><span class="p">()</span> </pre></div> <p>En el script se importa un modulo, <code>ril_config</code>, que es el que contiene las claves de mi cuenta de Pocket, este modulo sería algo similar a esto (evidentemente los valores son falsos):</p> <div class="codehilite"><pre><span class="c"># ril credentials</span> <span class="n">RIL_APIKEY</span> <span class="o">=</span> <span class="s">&#39;987u1ksjsdfRk54kKLKL34jkjij9945k&#39;</span> <span class="n">RIL_USERNAME</span> <span class="o">=</span> <span class="s">&#39;usuario&#39;</span> <span class="n">RIL_PASSWORD</span> <span class="o">=</span> <span class="s">&#39;ADRKSD-Xk3kj5kjljFl&#39;</span> </pre></div> <p>Por lo tanto para hacerlo funcionar necesitamos crear un fichero <code>ril_config.py</code> con las credenciales de cada uno para Pocket. Los campos <code>RIL_USERNAME</code> y <code>RIL_PASSWORD</code> se corresponden evidentemente con el usuario y la contraseña que tengamos para el servicio. El otro campo, <code>RIL_APIKEY</code> es una clave que podemos obtener en <a href="http://getpocket.com/api/signup/">esta página</a> para registrar nuestra aplicación (en este caso nuestro script) y que pueda acceder de forma autorizada a la API de Pocket.</p> <h3 id="copia_de_seguridad_de_las_urls_de_pocket">Copia de seguridad de las urls de Pocket</h3> <p>Del mismo modo, aprovechando la misma API que empleo en el anterior script, he creado otro script que ejecuto regularmente con cron, que me guarda una copia en mi disco duro con todas las urls que tengo guardadas en Pocket. Vamos, una copia de seguridad, uno nunca sabe cuando este tipo de servicios pueden dejar de funcionar. Estas direcciones las guardo en un fichero con formato <a href="https://es.wikipedia.org/wiki/Org-mode">Org-mode</a></p> <div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span> <span class="c"># -*- coding: utf8 -*-</span> <span class="sd">&quot;&quot;&quot;</span> <span class="sd"> get.py: Get the urls stored in Read it Later &amp; save them in a Org-mode file</span> <span class="sd">&quot;&quot;&quot;</span> <span class="n">__author__</span> <span class="o">=</span> <span class="s">&quot;joe di castro &lt;joe@joedicastro.com&gt;&quot;</span> <span class="n">__license__</span> <span class="o">=</span> <span class="s">&quot;GNU General Public License version 3&quot;</span> <span class="n">__date__</span> <span class="o">=</span> <span class="s">&quot;18/06/2012&quot;</span> <span class="n">__version__</span> <span class="o">=</span> <span class="s">&quot;0.1&quot;</span> <span class="k">try</span><span class="p">:</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">readitlater</span> <span class="kn">import</span> <span class="nn">ril_config</span> <span class="kn">as</span> <span class="nn">config</span> <span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span> <span class="c"># Checks the installation of the necessary python modules</span> <span class="k">print</span><span class="p">((</span><span class="n">os</span><span class="o">.</span><span class="n">linesep</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s">&quot;An error found importing one module:&quot;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">()[</span><span class="mi">1</span><span class="p">]),</span> <span class="s">&quot;You need to install it&quot;</span><span class="p">,</span> <span class="s">&quot;Stopping...&quot;</span><span class="p">]))</span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="kn">import</span> <span class="nn">os</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Main section&quot;&quot;&quot;</span> <span class="n">api</span> <span class="o">=</span> <span class="n">readitlater</span><span class="o">.</span><span class="n">API</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">RIL_APIKEY</span><span class="p">,</span> <span class="n">config</span><span class="o">.</span><span class="n">RIL_USERNAME</span><span class="p">,</span> <span class="n">config</span><span class="o">.</span><span class="n">RIL_PASSWORD</span><span class="p">)</span> <span class="n">items</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">state</span><span class="o">=</span><span class="s">&quot;unread&quot;</span><span class="p">)</span> <span class="n">lista</span> <span class="o">=</span> <span class="n">items</span><span class="p">[</span><span class="s">&quot;list&quot;</span><span class="p">]</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">&quot;ril_urls.org&quot;</span><span class="p">,</span> <span class="s">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">output</span><span class="p">:</span> <span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;* Read It Later URLs&quot;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">lista</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;** {0}{1}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">k</span><span class="p">[</span><span class="s">&#39;title&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">&quot;utf8&quot;</span><span class="p">),</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">))</span> <span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot; [[{0}][Enlace]]{1}{1}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">k</span><span class="p">[</span><span class="s">&#39;url&#39;</span><span class="p">]</span><span class="o">.</span> <span class="n">encode</span><span class="p">(</span><span class="s">&quot;utf8&quot;</span><span class="p">),</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">))</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span> <span class="n">main</span><span class="p">()</span> </pre></div> <h2 id="conclusi+n">Conclusión</h2> <p>Newsbeuter no es para todo el mundo, por supuesto, la gran mayoría considerarían decimonónico el emplear un interfaz de texto en vez de uno gráfico. Muchos incluso llamarían herejía a usar el teclado en vez de el ratón (aunque luego se vuelvan locos con las pantallas táctiles). Lo respeto y lo entiendo, pero para aquellos que aman su tiempo y no están dispuestos a desperdiciarlo, deberían darle una oportunidad a esta aplicación.</p>joe di castroMon, 18 Jun 2012 23:26:00 +0200http://joedicastro.com/productividad-linux-newsbeuter.htmlproductividadlinuxncursesrsspython