logo

Suletuxe.de
Linux - Nutzer
helfen
Linux - Nutzern

Willkommen, Gast. Bitte Login oder Registrieren.
08. Dezember 2023, 23:36:44
Übersicht Hilfe Suche Login Registrieren

Amateurfunk Sulingen
Diskussions- und Newsboard der Linux Interessen Gruppe Suletuxe  |  allgemeine Kategorie  |  Tutorials  |  Thema: ytfzf - Youtube und Co. im Terminal Browsen « zurück vorwärts »
Seiten: [1] nach unten Drucken
   Autor  Thema: ytfzf - Youtube und Co. im Terminal Browsen  (Gelesen 368 mal)
Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
ytfzf - Youtube und Co. im Terminal Browsen
« am: 04. November 2023, 06:53:05 »



Einleitung:

Hallo Suletuxe,

Durch die weitere Vertiefung und Einarbeitung in fzf bin ich noch auf ein weiteres tolles Projekt gestoßen.

Was ist ytfzf?



ytfzf verwendet fzf, um ein übersichtliches Menü verschiedener Videoplattformen im Terminal anzuzeigen, mit dessen Hilfe man diese Plattform dann komfortabel durchsuchen kann. In den meisten Fall wird dies dazu verwendet, um nach Videos auf Youtube zu suchen (Standard verhalten). Es ist aber auch möglich, alternativ Plattformen wie z.B. https://odysee.com/ damit zu durchsuchen. Bzw. es lassen sich auch eigene Scraper (So werden die Addons genannt, die die Videoplattformen abrufen) anlegen.

Dabei sei besonders zu erwähnen, dass ytfzf eines der wenigen Projekte ist, die in der lage sind auch Vorschaubilder (Tumbnails) in einem unterstützten Terminal (wie z.b. kitty) zu den Videos darzustellen.

Hat man nun ein Video gefunden, kann man nun verschiedene Dinge damit machen. Man kann es sich z.b. in seinem Lieblings Mediaplayer (Standard ist mpv) wiedergeben lassen oder auch in der gewünschten Auflösung mithilfe von yt-dlp herunterladen (Bitte AGBs der zuständigen Plattform beachten). Beim Download wird die Konfigurationsdatei von yt-dlp mit berücksichtigt.

Es lässt sich mit ytfzf auch eine lokale Liste von Kanälen anlegen, die von ytfzf abgerufen werden können. Um z.B. Datensparsam Kanäle zu abonnieren. Dafür siehe ytfzf(5)

Paketinformationen:







Benutzung:

In der einfachsten Form kann man ytfzf benutzten, indem man einfach den Befehl ohne weitere Parameter abschickt. ytfzf fragt dann nach einem Suchbegriff nach und führt eine Suche auf YouTube durch. Man kann, wenn man möchte, aber natürlich gleich einen Suchbegriff dahinter schreiben.

Um ytfzf aus seinem Menü heraus komfortable zu bedienen, gibt es ein paar Tastenkürzel, siehe hier für die vollständige Liste. Die Wichtigsten in meinem Gebrauch sind diese Hier:

Code:

download
alt-d (download_shortcut)

audio only
alt-m (audio_shortcut)

print link
alt-l (print_link_shortcut)

new search
alt-s (search_again_shortcut)

scrape next page
ctrl-p (next_page_action_shortcut)

Besonders STRG+p sei hier hervorgehoben, um weitere Videovorschläge zu laden (Standard sind 20)

Die wichtigsten Kommandoparameter entnimmt bitte aus meiner Navi ytfzf.cheat Datei. Für die vollständige Liste konsultiert bitte das Handbuch ytfzf(1)

Konfiguration:

Die meisten Kommandozeilen Parameter, die ytfzf bietet, lassen sich über dessen Konfigurationsdatei dauerhaft einstellen. Dafür siehe ytfzf(5)

Zwei für den ein oder anderen wichtige Optionen sind:

Code:

$sub_link_count
The amount of videos to scrape per channel when getting subscriptions.
default: 2

$show_thumbnails
Whether or not to show thumbnails in fzf.
default: 0


Hoffe für den ein oder anderen ist dieses Tool auch nützlich und wie immer würde ich mich über Feedback freuen.

LG
Sebastian
« Letzte Änderung: 11. November 2023, 15:37:12 von Sebastian » Gespeichert

Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
ytfzf - Interessante Linux Kanäle
« Antwort #1 am: 04. November 2023, 12:24:00 »

Ich werde hier mal eine Liste mit interessanten Video-Kanälen posten, die Linux hauptsächlich behandeln.

Die Liste werde ich in Form von ytfzf Befehlen bzw. bei der Youtube Plattform in Subscription Links für die ${XDG_CONFIG_HOME}/ytfzf/subscriptions Datei posten. Wenn ein Content Creator seine Inhalte auch auf anderen Plattformen wie z.b. https://odysee.com pflegt, dann werde ich nur diese mit auflisten.

Odysee - Deutschsprachige Kanäle

Code:

ytfzf -c O --sort @LinuxGuides
ytfzf -c O --sort @sempervideo

Odysee - Englischsprachige Kanäle

Code:

ytfzf -c O --sort @DistroTube
ytfzf -c O --sort @BrodieRobertson

Alle Odysee Kanäle in einem Aufruf zusammen gefasst:

Code:

ytfzf --sort -cM :NEXT -c O '@DistroTube' :NEXT -c O '@LinuxGuides' :NEXT -c O '@sempervideo' :NEXT -c O '@BrodieRobertson'

YouTube - Deutschsprachige Kanäle

Code:

https://www.youtube.com/channel/UCNDn2bb2AHVCliErAwA-45g #Nicht_der_Weisheit_letzter_Schluß
https://www.youtube.com/channel/UC1FC90ObOrYdfsPposnbbMQ #So_n_Typ_im_Internet

YouTube - Englischsprachige Kanäle

Code:

https://www.youtube.com/channel/UCxQKHvKbmSzGMvUrVtJYnUA #Learn_Linux_TV
https://www.youtube.com/channel/UCtYg149E_wUGVmjGz-TgyNA #Titus_Tech_Talk
https://www.youtube.com/channel/UCg6gPGh8HU2U01vaFCAsvmQ #Chris_Titus_Tech
https://www.youtube.com/channel/UCbiGcwDWZjz05njNPrJU7jA #ExplainingComputers
https://www.youtube.com/channel/UCMiyV_Ib77XLpzHPQH_q0qQ #Veronica_Explains
« Letzte Änderung: 19. November 2023, 14:14:13 von Sebastian » Gespeichert

Andreas
Administrator
*****

Offline

Einträge: 1086



Linux von Innen

Profil anzeigen
Re:ytfzf - Youtube und Co. im Terminal Browsen
« Antwort #2 am: 04. November 2023, 17:18:42 »

Absolut geil!
Die Möglichkeiten sind wirklich gigantisch. Ich werde auf navi umstellen (nach und nach) und ytfzf einsetzen. Das schlägt jede Textdatei und jedes Notizbuch...

LG
Andreas
Gespeichert

Wissen ist das einzige Gut, das mehr wird, wenn man es teilt - wenn es Menschen gibt, die es weitergeben, und es Menschen gibt, die bereit sind, dieses Geschenk auch unter eigenem Einsatz anzunehmen.


Freiheit zu erkämpfen reicht nicht. Man muss sie auch verteidigen.
Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
ytfzf - Subscription aktualisiert
« Antwort #3 am: 09. November 2023, 18:55:19 »

Die Subscription mit einem englischen YouTuber erweitert:

Code:
https://www.youtube.com/channel/UCMiyV_Ib77XLpzHPQH_q0qQ #Veronica_Explains
Gespeichert

Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
ytfzf - Subscription aktualisiert
« Antwort #4 am: 12. November 2023, 15:46:44 »

Weitere interessante Kanäle hinzugefügt.

Odysee - Deutschsprachige Kanäle
Code:

ytfzf -c O --sort @sempervideo

YouTube - Deutschsprachige Kanäle
Code:

https://www.youtube.com/channel/UC1FC90ObOrYdfsPposnbbMQ #So_n_Typ_im_Internet
Gespeichert

Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
ytfzf - Autocomplete Bash Script
« Antwort #5 am: 18. November 2023, 09:27:34 »

Hallo Suletuxe,

Da ytfzf noch kein Autocomplete hat und ich noch etwas Übung mit der Autocomplete Funktion der Bash brauche. Hatte ich mir diesen Befehl als nächsten herausgesucht, da er ohne Unterbefehle arbeitet, erschien er mir als Übung gut geeignet.

Da ich noch ein wenig mehr Logik in das Autocomplete hereinbringen wollte, habe ich versucht jede Option auf der Befehlszeile zu erkennen, so dass diese beim Autocomplete nicht mehr vorgeschlagen wird. Da ich glaube bei ytfzf keine Option dabei ist, wo es Sinn macht diese zweimal anzugeben. Das ist mir leider nicht ganz gelungen. Und zwar werden Optionen mit einem "=" Zeichen zum Schluss aus der Auswahl der Autocomplete Möglichkeiten nicht entfernt, warum auch immer. 

Vielleicht kann mir da jemand auf die Sprünge helfen, warum diese Optionen nicht entfernt werden?

Code:

#!/usr/bin/env bash

_ytfzf() {
    # Array mit ytfzf Optionen
    local options=(
        '-a'
        '-A'
        '--async-thumbnails'
        '--audio-pref='
        '-c'
        '--channel-link='
        '-d'
        '-D'
        '--detach'
        '--disable-actions'
        '--disable-back'
        '--disable-submenus'
        '-e'
        '-f'
        '--fancy-subs'
        '--features='
        '--force-invidious'
        '--force-youtube'
        '--format-sort='
        '-h'
        '-H'
        '--history-clear='
        '-i'
        '-I'
        '--ii='
        '--info-action='
        '--info-wait'
        '--keep-cache'
        '--keep-vars'
        '-l'
        '-L'
        '--list-addons'
        '-m'
        '--max-threads='
        '--multi-search'
        '-n'
        '--notify-playing'
        '--nsfw'
        '--odysee-video-count'
        '--pages'
        '--pages-start='
        '--preview-side='
        '-q'
        '-r'
        '--region='
        '--rii'
        '-s'
        '-S'
        '--scrape+='
        '--scrape-='
        '--single-threaded'
        '--skip-thumb-download'
        '--sort'
        '--sort-by='
        '--sort-name='
        '--submenu-opts='
        '-t'
        '-T'
        '--thumbnail-log'
        '--type='
        '-u'
        '--upload-date='
        '--version'
        '--version-all'
        '--video-duration='
        '--video-pref='
        '-x'
        '--ytdl-opts='
        '--ytdl-path='
        '--ytdl-pref='
    )
    local cur="${COMP_WORDS[COMP_CWORD]}" # Index Positions des Cursor
    local index arg
    # Erzeuge eigenes comp_words Array. Um Probleme mit "=" Zeichen in $COMP_WORDBREAKS zu umgehen
    mapfile -t comp_words < <(compgen -W "${COMP_LINE}")
    # Loop durch alle Argumente auf der Befehlzeile
    for arg in "${comp_words[@]:1}"; do
        # Loop durch alle ytfzf Optionen um diese mit dem Argumenten auf der
        # Befehlzeile zu vergleichen. Bei übereinstimmung wird die Option entfernt
        for index in "${!options[@]}"; do
            [[ "${arg}" == "${options[index]}" ]] &&
                unset "options[index]"
        done
    done
    # Prüfe ob der Coursor nicht am Anfang steht, um dann eine Autovervollständigung
    # Aus dem noch vorhanden Optionen auszulösen.
    ((COMP_CWORD)) &&
        mapfile -t COMPREPLY < <(
            compgen -W "${options[*]}" -- "${cur}"
        )
}
complete -F _ytfzf ytfzf


Das Skript kann wieder unter die üblichen Pfade eingebunden werden:

Code:

/etc/bash_completion.d/ # Systemweit für alle User
$XDG_DATA_HOME/bash-completion # Für den Einzelnen User
~/.local/share/bash-completion # Falls man die $XDG_DATA_HOME Variable nicht gesetzt hat.


LG
Sebastian
« Letzte Änderung: 20. November 2023, 20:29:39 von Sebastian » Gespeichert

Andreas
Administrator
*****

Offline

Einträge: 1086



Linux von Innen

Profil anzeigen
Re:ytfzf - Youtube und Co. im Terminal Browsen
« Antwort #6 am: 18. November 2023, 10:54:10 »

Ich kann nur vermuten Sebastian (ich habe im Moment keine Zeit selbst zu forschen). Das "=" wird vermutlich nicht erkannt. Entweder, weil es per se nicht erkannt wird, oder weil Du es escapen musst. Nach Regex ist es zwar nicht nötig das "=" zu escapen - aber das hier ist ja auch kein Regex Ausdruck...

LG
Andreas
Gespeichert

Wissen ist das einzige Gut, das mehr wird, wenn man es teilt - wenn es Menschen gibt, die es weitergeben, und es Menschen gibt, die bereit sind, dieses Geschenk auch unter eigenem Einsatz anzunehmen.


Freiheit zu erkämpfen reicht nicht. Man muss sie auch verteidigen.
Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
Re:ytfzf - Youtube und Co. im Terminal Browsen
« Antwort #7 am: 18. November 2023, 14:01:36 »

Danke Andreas,

Es ist auf jedenfall ein Escape Problem da Bash das "=" Zeichen als Zuweisungsoperator für Variablen verwendet. Ich komm nur momentan nicht darauf an welcher stelle ich es Escapen muss, da habe ich zurzeit einen Knotten im Kopf 

Vielleicht gibt es auch eine Möglichkeit für eine gewisse Zeit die Bedeutung dieses Operators ganz abzuschalten. für die Kritische stelle im Code bei den Loop-Schleifen. Werde mich da mal weiter reinlesen 

LG
Sebastian
Gespeichert

Andreas
Administrator
*****

Offline

Einträge: 1086



Linux von Innen

Profil anzeigen
Re:ytfzf - Youtube und Co. im Terminal Browsen
« Antwort #8 am: 18. November 2023, 14:52:53 »

Du müsstest den gesamten String in Anführungszeichen (die einfachen, nicht die doppelten) setzen: https://www.baeldung.com/linux/bash-escape-characters . Es kann auch sein, dass einfach ein Backslash vor dem = reicht - ausprobieren...

LG
Andreas
« Letzte Änderung: 18. November 2023, 14:54:21 von Andreas » Gespeichert

Wissen ist das einzige Gut, das mehr wird, wenn man es teilt - wenn es Menschen gibt, die es weitergeben, und es Menschen gibt, die bereit sind, dieses Geschenk auch unter eigenem Einsatz anzunehmen.


Freiheit zu erkämpfen reicht nicht. Man muss sie auch verteidigen.
Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
Re:ytfzf - Youtube und Co. im Terminal Browsen
« Antwort #9 am: 18. November 2023, 18:22:11 »

Habe ich schon getan, habe alle Werte die im options Array in einfache Anführungszeichen gesetzt. Auch das Doppel escapen zuätzlich mit einem \ hat nichts gebracht auser das dieser dann Literal mit im Wert drin steht.

Habe vor der Loop mal ein declare -p COMP_WORDS eingebaut, damit ich sehe was da passiert:

Code:

ytfzf --ytdl-pref=declare -a COMP_WORDS=([0]="ytfzf" [1]="--ytdl-pref" [2]="=")
Tab wurde nach --ytdl-pref= gedrückt

Man sieht, das nach dem druck der Tab Taste warum auch immer das "=" Zeichen vom Argument abgetrennt wird und ein neues Argument für sich und damit einen neuen Wert im Array bildet, ich verstehe nur noch nicht ganz warum das passiert.

Edit:

Bin auch schon auf der Suche nach einem Befehl der auch Optionen mit einem "=" Zeichen beinhaltet, um mir da beim Autocomplete Code vielleicht was abzuschauen. Problem ist, anscheint hat niemand so eine Logik implementiert zu haben, dass Optionen nach dem Einfügen aus den Vorschlägen entfernt werden. Die scheinen alle damit zu Frieden zu sein, wenn einfach alle Angeboten werden.

So langsam glaube ich auch, warum das keiner macht 

Da kann ich erst mal froh sein, das dies bei allen anderen Optionen funktioniert. Vielleicht komme ich später noch darauf. 

LG

Sebastian
« Letzte Änderung: 18. November 2023, 18:55:02 von Sebastian » Gespeichert

Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
ytfzf - Odysee Kanäle in einem Aufruf zusammen gefasst
« Antwort #10 am: 19. November 2023, 14:12:15 »

Sektion der Odysee Kanäle erweitert:

Alle Odysee Kanäle in einem Aufruf zusammen gefasst:

Code:

ytfzf --sort -cM :NEXT -c O '@DistroTube' :NEXT -c O '@LinuxGuides' :NEXT -c O '@sempervideo' :NEXT -c O '@BrodieRobertson'


LG
Sebastian
« Letzte Änderung: 19. November 2023, 14:13:37 von Sebastian » Gespeichert

Sebastian
Sr. Member
****

Offline

Einträge: 311





Profil anzeigen
Re:ytfzf - Lösung Autocomplete Script Bug
« Antwort #11 am: 20. November 2023, 20:53:21 »

@ Andreas

Habe endlich eine Lösung für das "=" Zeichen Problem beim Autocomplete gefunden. Um genau zu sein sogar zwei Lösungen mit unterschiedlichen Ansetzten:

Lösung 1:

Code:

#!/usr/bin/env bash

_ytfzf() {
    # Array mit ytfzf Optionen
    local options=(
        '-a'
        '-A'
        '--async-thumbnails'
        '--audio-pref='
        '-c'
        '--channel-link='
        '-d'
        '-D'
        '--detach'
        '--disable-actions'
        '--disable-back'
        '--disable-submenus'
        '-e'
        '-f'
        '--fancy-subs'
        '--features='
        '--force-invidious'
        '--force-youtube'
        '--format-sort='
        '-h'
        '-H'
        '--history-clear='
        '-i'
        '-I'
        '--ii='
        '--info-action='
        '--info-wait'
        '--keep-cache'
        '--keep-vars'
        '-l'
        '-L'
        '--list-addons'
        '-m'
        '--max-threads='
        '--multi-search'
        '-n'
        '--notify-playing'
        '--nsfw'
        '--odysee-video-count'
        '--pages'
        '--pages-start='
        '--preview-side='
        '-q'
        '-r'
        '--region='
        '--rii'
        '-s'
        '-S'
        '--scrape+='
        '--scrape-='
        '--single-threaded'
        '--skip-thumb-download'
        '--sort'
        '--sort-by='
        '--sort-name='
        '--submenu-opts='
        '-t'
        '-T'
        '--thumbnail-log'
        '--type='
        '-u'
        '--upload-date='
        '--version'
        '--version-all'
        '--video-duration='
        '--video-pref='
        '-x'
        '--ytdl-opts='
        '--ytdl-path='
        '--ytdl-pref='
    )
    local cur="${COMP_WORDS[COMP_CWORD]}" # Index Positions des Cursor
    local index arg
    # Erzeuge eigenes comp_words Array. Um Probleme mit "=" Zeichen in $COMP_WORDBREAKS zu umgehen
    mapfile -t comp_words < <(compgen -W "${COMP_LINE}")
    # Loop durch alle Argumente auf der Befehlzeile
    for arg in "${comp_words[@]:1}"; do
        # Loop durch alle ytfzf Optionen um diese mit dem Argumenten auf der
        # Befehlzeile zu vergleichen. Bei übereinstimmung wird die Option entfernt
        for index in "${!options[@]}"; do
            [[ "${arg}" == "${options[index]}" ]] &&
                unset "options[index]"
        done
    done
    # Prüfe ob der Coursor nicht am Anfang steht, um dann eine Autovervollständigung
    # Aus dem noch vorhanden Optionen auszulösen.
    ((COMP_CWORD)) &&
        mapfile -t COMPREPLY < <(
            compgen -W "${options[*]}" -- "${cur}"
        )
}
complete -F _ytfzf ytfzf

Bei dieser Lösung wird die ganze Zeile neu in $comp_words eingelesen, und in einzelne Argumente aufgeteilt, die dann wiederum mit dem options array abgeglichen werden können, um bereits vorhanden Optionen auf der Befehlszeile aus den Vorschlägen zu entfernen. Die BASH eigene Variable, die die einzelenen Argumente beinhaltet hat leider ein Problem mit ein paar Zeichen unteranderem dem "=" Zeichen. Die Begründung dazu liegt in der Variable

COMP_WORDBREAKS
Zitat:
The set of characters that the readline library treats as word separators when performing word completion.  If COMP_WORDBREAKS is unset, it loses its special properties, even if it is subsequently reset.

Die folgenden Inhalt hat:

Code:

echo $COMP_WORDBREAKS
"'><=;|&(:

Lösung 2:

Die zweite Lösung beinhaltet eine Hilfsfunktion aus dem Paket bash-completion das warscheinlich so gut wie überall installiert sein müsste.

Code:

#!/usr/bin/env bash

_ytfzf() {
    local options=(
        '-a'
        '-A'
        '--async-thumbnails'
        '--audio-pref='
        '-c'
        '--channel-link='
        '-d'
        '-D'
        '--detach'
        '--disable-actions'
        '--disable-back'
        '--disable-submenus'
        '-e'
        '-f'
        '--fancy-subs'
        '--features='
        '--force-invidious'
        '--force-youtube'
        '--format-sort='
        '-h'
        '-H'
        '--history-clear='
        '-i'
        '-I'
        '--ii='
        '--info-action='
        '--info-wait'
        '--keep-cache'
        '--keep-vars'
        '-l'
        '-L'
        '--list-addons'
        '-m'
        '--max-threads='
        '--multi-search'
        '-n'
        '--notify-playing'
        '--nsfw'
        '--odysee-video-count'
        '--pages'
        '--pages-start='
        '--preview-side='
        '-q'
        '-r'
        '--region='
        '--rii'
        '-s'
        '-S'
        '--scrape+='
        '--scrape-='
        '--single-threaded'
        '--skip-thumb-download'
        '--sort'
        '--sort-by='
        '--sort-name='
        '--submenu-opts='
        '-t'
        '-T'
        '--thumbnail-log'
        '--type='
        '-u'
        '--upload-date='
        '--version'
        '--version-all'
        '--video-duration='
        '--video-pref='
        '-x'
        '--ytdl-opts='
        '--ytdl-path='
        '--ytdl-pref='
    )
    local cur prev words cword
    _init_completion -n '='
    for i in "${!options[@]}"; do
        for arg in "${words[@]}"; do
            [[ "${arg}" == "${options[i]}" ]] &&
                unset "options[i]"
        done
    done
    ((COMP_CWORD)) &&
        mapfile -t COMPREPLY < <(
            compgen -W "${options[*]}" -- "${cur}"
        )
}
complete -F _ytfzf ytfzf

Die Rede ist von der Funktion _init_completion mit der man unter anderem ein Zeichen aus der Variable $COMP_WORDBREAKS entfernen kann, ohne das Autocomplete von anderen Befehlen kaputtzumachen.

Die ganze Logik für das Autocomplete von ytfzf ist vielleicht ein wenig übertrieben. Mir ging es aber hauptsächlich darum das mal gemacht zu haben, damit ich die Abläufe besser verstehe.

Und ich muss sagen ich habe einiges neues wieder dazu gelernt, jetzt habe ich ein gutes verständiges über die BASH Autocomplete Funktion erhalten.

LG
Sebastian
Gespeichert

Seiten: [1] nach oben Drucken 
Diskussions- und Newsboard der Linux Interessen Gruppe Suletuxe  |  allgemeine Kategorie  |  Tutorials  |  Thema: ytfzf - Youtube und Co. im Terminal Browsen « zurück vorwärts »
Gehe zu: 


Login mit Username, Passwort und Session Länge

 Es wird die Verwendung "Blink"-basierter Browser und mindestens 1024x768 Pixel Bildschirmauflösung
für die beste Darstellung empfohlen
 
freie Software für freie Menschen!
Powered by MySQL Powered by PHP Diskussions- und Newsboard der Linux Interessen Gruppe Suletuxe | Powered by YaBB SE
© 2001-2004, YaBB SE Dev Team. All Rights Reserved.
- modified by Andreas Richter (DF8OE)
Valid XHTML 1.0! Valid CSS!