En otras ocasiones ya hemos explicado como acceder al contenido de GDrive mediante el addon de KODI y como importar contenido mediante FTP . El problema de acceder a contenido 4K desde el addon de KODI es que este resulta muy lento dando problemas como congelaciones momentáneas o retardos indeseados, combinando PlexDrive y exportando el contenido vÃa FTP funciona razonablemente bien pero mediante la exportación HTTP ganaremos en rendimiento además de que si el servidor está nateado será mas sencillo utilizarlo desde el exterior ya que HTTP utiliza un único puerto.
En este artÃculo utilizaremos PlexDrive y Nginx para servir el contenido de GDrive a un KODI instalado en AndroidTV.
El artÃculo se compone de varios pasos:
PlexDrive:
Debemos tener en cuenta que el acceso a GDrive desde PlexDrive es de solo lectura:
Please note that plexdrive doesn't currently support writes (adding new files or modifications), it only supports reading existing files and deletion.
En mi caso voy a utilizar una jail bajo IOCage desde la que importaré el contenido de GDrive y lo serviré por FTP.
Montamos el sistema de ficheros por FUSE en el padre y se lo pasamos a la jail para no tener que modificar permisos especiales en esta.
Instalamos el software necesario:
Cargamos el módulo fusefs:
Ahora deberÃa existir un dispositivo llamado fuse:
crw-rw-rw- 1 root operator 0xe3 Nov 30 23:28 /dev/fuse
Configuramos el SO para que cargue el módulo de forma automática en cada arranque:
kld_list="fusefs ..."
Averiguamos el drive-id copiándolo desde la URL del navegador mostrada cuando accedemos a GDrive, en mi caso la URL tiene el siguiente aspecto:
https://drive.google.com/drive/folders/0ANN6pzUlNUgXUk9PVA
El drive-id es: 0ANN6pzUlNUgXUk9PVA
Nos bajamos PlexDrive, podemos ver las versiones disponibles en
este enlace de github
chmod 700 plexdrive-freebsd-amd64
Creamos el directorio donde montaremos la unidad de GDrive:
Arrancamos manualmente PlexDrive:
1. Please go to https://console.developers.google.com/
2. Create a new project
3. Go to library and activate the Google Drive API
4. Go to credentials and create an OAuth client ID
5. Set the application type to 'other'
6. Specify some name and click create
7. Enter your generated client ID:
Al acceder a la URL mostrada nos aparecerá la siguiente interfaz donde debemos darle al botón de la derecha “CREAR PROYECTO”:
Indicamos un nombre y le damos a crear:
Ya tenemos el proyecto creado:
Activamos la API de Google drive en el proyecto, para ello accedemos a “API y servicios” -> Biblioteca:
Buscamos “Google drive api” y clickamos sobre él:
Le damos a habilitar:
Nos aparecerá la siguiente ventana desde la que debemos crear las credenciales de acceso:
Le damos a “CREAR CREDENCIALES”:
Seleccionamos “ID de cliente OAuth”:
Nos aparecerá la siguiente ventana donde debemos darle a “CONFIGURAR PANTALLA DE CONSENTIMIENTO”:
En User Type indicamos: Externos y le damos a “CREAR”:
Rellenamos los datos obligarotios del formulario y le damos a “GUARDAR Y CONTINUAR”:
No necesitamos ningún tipo de permiso especial, asà que le damos a “GUARDAR Y CONTINUAR”:
Agregamos un usuario, le damos a “ADD USER”:
Indicamos el usuario y le damos a “AGREGAR”:
DeberÃa de aparecer en la lista, le damos a “GUARDAR Y CONTINUAR”:
Aparecerá un resumen, le damos a “VOLVER AL PANEL”:
Nos llevará a la “Pantalla de consentimiento de OAuth”, desde aquà accedemos a la sección “Credenciales”:
Le damos a “CREAR CREDENCIALES” de nuevo:
Seleccionamos “ID de cliente OAuth”:
En tipo de aplicación selccionamos “App de escritorio”, le damos un nombre y clickamos sobre “CREAR”:
Nos mostrará la siguiente información:
Podemos ver el cliente OAuth:
Seguimos con la consola de PlexDrive:
1. Please go to https://console.developers.google.com/
2. Create a new project
3. Go to library and activate the Google Drive API
4. Go to credentials and create an OAuth client ID
5. Set the application type to 'other'
6. Specify some name and click create
7. Enter your generated client ID: XXXXXXXXXXXXXXXXXXXXXXX
8. Enter your generated client secret: YYYYYYYYYYYYYYYYYYY
Go to the following link in your browser https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=ZZZZZZZZZZZZ-270hoqea0pinv0nc3sbpfkuja68alask.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&state=state-token
Accedemos a la URL que nos indica PlexDrive mediante el usuario anteriormente autorizado:
Aparecerá el siguiente mensaje donde le damos a continuar:
Le volvemos a dar a continuar:
Nos mostrará un código:
En la consola pegamos dicho código:
Paste the authorization code: XXXXXXXXXXXXXXXXXXXX
Le damos a Ctrl+C y demonizamos el montaje de la unidad de GDrive:
#! /bin/sh
#
# $FreeBSD$
#
# PROVIDE: gdrive
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
name="gdrive"
rcvar="${name}_enable"
extra_commands="status"
start_cmd="${name}_start"
stop_cmd="${name}_stop"
status_cmd="${name}_status"
gdrive_start(){
echo "Clearing cache files: ${name}"
rm /root/.plexdrive/cache.bolt
echo "Starting service: ${name}"
/usr/sbin/daemon -S -p /var/run/${name}.pid -T gdrive -u root /root/plexdrive-freebsd-amd64 mount -o allow_other -v 3 --drive-id=0ANN6pzUlNUgXUk9PVA /mnt/gdrive
}
gdrive_stop(){
if [ -f /var/run/${name}.pid ]; then
echo "Stopping service: ${name}"
kill -s INT $(cat /var/run/${name}.pid)
sleep 3
else
echo "It appears ${name} is not running."
fi
}
gdrive_status(){
if [ -f /var/run/${name}.pid ]; then
echo "${name} running with PID: $(cat /var/run/${name}.pid)"
else
echo "It appears ${name} is not running."
fi
}
load_rc_config ${name}
run_rc_command "$1"
Asignamos los permisos necesarios:
chown root:wheel /usr/local/etc/rc.d/gdrive
Habilitamos el servicio y lo arrancamos:
service gdrive start
Ahora importaremos el directorio /mnt/gdrive del padre a la jail.
Creamos el directorio en la jail:
mkdir /mnt/gdrive
exit
Importamos el directorio mediante el comando fstab de IOCage:
Successfully added mount to GDrive's fstab
Nginx:
Ahora accedemos a la jail y montamos el servidor, el acceso desde el exterior será por HTTPS ya que requeriremos de autenticación para acceder al contenido y no queremos que dichas credenciales se vean comprometidas, en cambio desde la LAN también serÃa conveniente utilizar HTTPS pero para ello deberÃamos de utilizar el nombre de dominio público desde los equipos LAN lo cual da problemas por el Hairpining , para resolver esto hay tres opciones:
- Montar un servidor DNS interno con RPZ y configurar los clientes internos para que utilicen dicho DNS.
- Modificar el fichero /etc//hosts de los clientes para que el dominio resuelva a la ip LAN, pero en mi caso no es posible por tratarse de un AndroidTV.
- Utilizar HTTP(opción por la que me decanté).
Instalamos Nginx y Socat ya que es una dependencia de ACME, la herramienta con la que emitiremos el certificado HTTPS:
Instalamos ACME:
Emitimos el certificado:
La configuración de Nginx es la vanilla pero con un include adicional:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include gdrive.alfaexploit.conf;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name gdrive.alfaexploit.com;
location / {
root /usr/local/www/nginx;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
}
}
Nuestra configuración especÃfica:
server {
listen 443 ssl default_server proxy_protocol;
server_name gdrive.alfaexploit.com;
set_real_ip_from 192.168.69.11;
real_ip_header proxy_protocol;
root /mnt/gdrive;
location / {
autoindex on;
auth_basic "Login Required";
auth_basic_user_file /usr/local/etc/nginx/.htpasswd;
}
ssl_certificate "/root/.acme.sh/gdrive.alfaexploit.com/fullchain.cer";
ssl_certificate_key "/root/.acme.sh/gdrive.alfaexploit.com/gdrive.alfaexploit.com.key";
}
# Direct IoT devices wich cant change /etc/hosts and evade hairpinning problem
server {
listen 80 default_server;
server_name _;
root /mnt/gdrive;
location / {
autoindex on;
auth_basic "Login Required";
auth_basic_user_file /usr/local/etc/nginx/.htpasswd;
}
}
# LetsEncrypt cert renew
server {
listen 81 default_server;
server_name _;
root /usr/local/www/nginx;
}
Tenemos Nginx en claro en el puerto 80/81, el primero es para los dispositivos IoT en la LAN como TVs que no pueden cambiar el fichero /etc/hosts y por lo tanto el hairpinning da problemas, estos acceden directamente al 80. Por otro lado si lo dejamos asà LetsEncrypt no podrá renovar el certificado ya que el docroot del puerto 80 es RO, en el HaProxy enviaremos el tráfico de LetsEncrypt al puerto 81 que está asociado a un docroot RW.
Generamos el fichero de credenciales:
El resultado final debe ser muy similar a este:
kr0m:$apr1$gypxo60s$6vKdmpNM3J8gJ7pdcLkeg/
Reiniciamos el servicio:
HaProxy:
En mi caso el tráfico es balanceado por un HaProxy donde se enviará el tráfico por HTTP en caso de tratarse de ACME renovando el certificado o por HTTPS en caso contrario, cuando sea por HTTPS se utilizará ProxyProtocol para asignar la ip origen de las peticiones:
frontend HTTP
bind :80
option forwardfor
# Allow http access only for LetsEncrypt:
acl letsencrypt path_beg /.well-known/acme-challenge/
http-request redirect scheme https unless letsencrypt
acl gdrive hdr(host) -i gdrive.alfaexploit.com
http-request deny if !gdrive
use_backend gdrive if gdrive
frontend HTTP-SSL
bind :443
mode tcp
acl gdrive_ssl req.ssl_sni -i gdrive.alfaexploit.com
tcp-request inspect-delay 2s
tcp-request content reject if !gdrive_ssl
use_backend gdrive_ssl if gdrive_ssl
# GDrive is a special case:
# Nginx:80 -> Direct IoT devices wich cant change /etc/hosts and evade hairpinning problem docroot: /mnt/gdrive RO
# Nginx:81 -> Letsencrypt docroot: /usr/local/www/nginx RW
backend gdrive
server gdrive 192.168.69.14:81 check
backend gdrive_ssl
mode tcp
option ssl-hello-chk
server gdrive 192.168.69.14:443 check sni req.ssl_sni send-proxy-v2
KODI:
Ahora toca añadir la fuente en KODI, accedemos a los parámetros de configuración:
Contenidos:
Videos:
Añadir videos:
Buscar:
Añadir sitio de red:
Añadimos nuestro servidor HTTP o HTTPS si accedemos desde fuera de la LAN, si accedemos desde fuera pondremos el nombre de dominio gdrive.alfaexploit.com si lo hacemos desde la LAN directamente la dirección ip del servidor Nginx, en todos los casos debemos indicar las credenciales definidas en el htaccess::
Ahora aparecerá en la lista de recursos:
Navegamos por el servidor HTTP y añadimos el directorio deseado:
Le damos a OK:
Configuramos como queremos “escrapear” el directorio y le damos a OK:
A partir de aquà ya podremos ver las pelÃculas en la sección correspondiente de KODI.
Token expirado:
Google genera los tokens de apps no publicadas en modo “Testing”:
- A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days.
Que traducido serÃa algo asÃ:
Un proyecto de Google Cloud Platform con una pantalla de consentimiento de OAuth configurada para un tipo de usuario externo y un estado de publicación de "Prueba" recibe un token de actualización que vence en 7 dÃas.
Esto provoca el siguiente error en PlexDrive cada 7 dÃas:
Response: {
"error": "invalid_grant",
"error_description": "Token has been expired or revoked."
}
Publicando la app esta limitación desaparecerÃa, pero para publicar una app se requieren muchos pasos adicionales como configuración de DNS con entradas especÃficas de Google y demás.
Una maner sencilla pero manual de resolverlo es entrando cada semana y regenarando el token del usuario, para ello eccedemos a la sección de credenciales del proyecto:
https://console.developers.google.com/apis/credentials
Le damos a editar al id del cliente anteriormente creado:
Le damos a “REESTABLECER SECRETO”:
Confirmamos que deseamos reestablecer el secreto:
Ahora debemos resetear PlexDrive desde cero, en mi caso primero paro la jail que sirve el contenido:
Paro el servicio:
Elimino la configuración de PlexDrive:
Arranco PlexDrive manualmente donde nos pedirá los datos de acceso de nuevo:
1. Please go to https://console.developers.google.com/
2. Create a new project
3. Go to library and activate the Google Drive API
4. Go to credentials and create an OAuth client ID
5. Set the application type to 'other'
6. Specify some name and click create
7. Enter your generated client ID: XXXXXXXXXXXXXXXXXXXXX
8. Enter your generated client secret: YYYYYYYYYYYYYYYYYYYY
Go to the following link in your browser https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=ZZZZZZZZZZZZ-270hoqea0pinv0nc3sbpfkuja68alask.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&state=state-token
Paste the authorization code: 4/1AX4XfWgwVi61FfxtHN0WpBUh_b3UvGhXfWscjb_B-oNQyl4zVniUtdqbQQg
Cuando haya conectado correctamente lo paramos:
Arrancamos el servicio:
Finalmente arrancamos la jail: