Enchufe inteligente, error configuración

Hace un par de día decidí adquirir un par de enchufes inteligentes, de la marca Teckin con capacidad WiFi, para poder controlar el consumo de algunos dispositivos electrónicos en casa.

Estos enchufes pueden ser controlados desde el Smartphone, usando la aplicación ‘Smart Life’ del fabricante Tuya, y permiten conocer el consumo en cada momento así como ser activados o desactivados de forma remota.

Enchufes Teckin

Además son compatibles con Alexa, Google Home, Amazon Echo… y funcionan tanto con Android como con iPhone.

Pero, es posible que al intentar configurarlos tengáis algún problema para enlazarlo con vuestra cuenta y hacerlos funcionar, por un error muy común con este tipo de dispositivos y la configuración de algunos routers de los distintos ISPs.

 

En mi caso a principio de año cambién de Vodafone a la fibra de Yoigo, por lo que me instalaron el router ZTE F680, que funciona bastante bien pero tiene algunas pegas como no poder ser configurado en modo bridge (por limitaciones impuestas por el ISP.

Tras intentar realizar una primera configuración sin éxito, terminé encontrando información en los foros de BandaAncha sobre el posible problema con este tipo de dispositivos de domótica y cómo solucionarlo.

El problema resulta estar en los servidores DNS que usa cada ISP, por lo que configurando el servidor de Google (8.8.8.8) en el router de Yoigo, el problema se soluciona.

 

En el caso más específico de estos enchufes, debemos tener en cuenta además otras limitaciones:

  • Solo funcionan con redes de 2.4 GHz.
  • El fabricante indica que no se use el canal 11 para la WiFi.
  • Para la configuración inicial, el smartphone debe estar conectado a la misma WiFi a la que queremos conectar el enchufe.
  • La seguridad debe ser WPA2-PSK con encriptación AES.

Teniendo esto en cuenta, la configuración es realmente sencilla, y una vez realizada podemos conectarnos desde cualquier lugar a los dispositivos (incluyendo desde fuera de casa con tu conexión 3G/4G).

Conceptos caducos.

Retomo el blog, tras mucho tiempo sin tiempo para actualizar, repasando algunos conceptos caducos pero aún presentes en la mayoría de empresas, que son origen de muchos problemas.

  1. Conocimiento es poder.
  2. Opacidad
  3. Horarios
  4. Jerarquías
  5. Enchufismo

Caducidad

Conocimiento es poder.

Fue Sir Francis Bacon quien pronuncio esta frase, pero estoy seguro de que cuando la dijo no pensaba en las connotaciones negativas de la misma.

Cierto es que disponer de conocimientos proporciona una ventaja sobre el resto, más aún cuando eres el único que los posee en su totalidad.

Pero en la actualidad este concepto puede perjudicar más que ayudar cuando hablamos del global, de la empresa, pues es un mundo donde el conocimiento se transmite a la velocidad de la luz y se encuentra a unos pocos clicks de distancia, son muchos los que han optado por defender su posición secuestrando dicho conocimiento.

Mucha veces es la inseguridad a perder ese poder o ventaja sobre los demás, la que ha llevado a muchos a crear espacios estancos donde puedan controlarlo todo mediante la exclusividad de los conocimientos que se aplican. De esta forma en muchas empresas se crean ‘chiringuitos’ donde alguien ostenta el máximo poder, controlando a quien trabaja para él y no permitiendo que nada salga del mismo.

¿Problemas?

Por una parte se convierten en ‘imprescindibles’, dado que son los únicos que lo saben todo. Por otra parte impiden la lógica evolución de tu negocio, el cambio necesario para mejorar y ser mejores, manteniéndose en desventaja contra otros competidores o generando altos costes al no permitir que se optimicen procesos o se creen mejores soluciones.

Y muy importante también es que la gente que cae en uno de estos departamentos estancos tiene poca movilidad dentro de la empresa, al limitarse su visión y conocimientos a lo que allí se hace, perdiéndose las ventajas de compartir experiencias y conocimientos con otros grupos dentro de la organización.

Opacidad.

opacidad

Del lat. opacĭtas, -ātis.

1. f. Cualidad de opaco.

opaco, ca

Del lat. opācus.

1. adj. Que impide el paso a la luz, a diferencia de diáfano.

2. adj. Oscuro, sombrío.

3. adj. Triste y melancólico.

Cuando hablo de opacidad me refiero a la falta de transparencia, a esas empresas donde la información apenas circula pero más allá de esos espacios estancos a los que me refería en el primer punto.

La falta de fluidez entre las capas o estratos dentro de la jerarquía de la empresa, cuando información importante sobre los objetivos y políticas de la empresa (o incluso su buena o mala marcha) no se transmite, manteniendo a quien está por debajo en tinieblas y sin saber qué se hace, hacia dónde se va o cómo encaja su trabajo dentro de la empresa.

El problema con este punto es el malestar que se genera, la inseguridad de no saber si lo que se hace es importante o no, o la incertidumbre sobre la viabilidad de la propia empresa cuando las cosas no van bien y surgen los rumores.

 

Horarios.

Este es un punto importante y muy en boga hoy en día con el tema de la conciliación laboral.

Dentro de las tareas que una persona puede realizar siempre habrá tareas para las que necesite interactuar directamente con otros, y tareas que puede realizar solo.

Hoy en día la tecnología nos permite ahorrarnos miles de euros en viajes para acudir a una reunión con un cliente (sobre todo si está en otro país), mediante tele o video conferencias.

Pero a nivel de empresa, aún sigue muy arraigado el concepto de horarios estrictos y poco flexibles que hay que cumplir a rajatabla, que pueden suponer un problema para quienes tengan familia y deban cuidar de ellos, para quienes son más productivos a horas del día distintas a las habituales, o para quien tiene que realizar un largo desplazamiento diario para acudir a un centro de trabajo.

Obviamente la actividad de una empresa debe regirse por un horario siempre que se pueda, pues ayuda a coordinar esfuerzos, pero hay que ser flexible cuando se pueda y la gente lo requiera.

Un padre o madre que pueda acudir sin prisas a recoger a sus hijos a la salida del colegio, o que pueda quedarse a trabajar en casa cuando lo requiera. Una persona que pueda ahorrarse 2-3 viajes semanales, ahorrando tiempo y dinero, cuando sus tareas y planificación lo permitan.

Todas esas personas valorarán más positivamente nuestra empresa y la comodidad que les proporcionamos, considerándolo un valor añadido.

Jerarquías.

De acuerdo, un barco siempre necesita un capitán, pero ese capitán debe liderar más que mandar, y sobre todo dejar que quienes le acompañen en su travesía hagan su trabajo.

El exceso de jerarquía, el exceso de personas que ostentan algún cargo con capacidad de decisión o de bloqueo, nos perjudican al hacer que nuestra empresa sea mucho menos ágil de lo que nos convendría.

En un mercado tan global, donde todo se sucede tan deprisa, ser lento es lo peor que puedes ser para competir y participar en los negocios.

Por ello tener un exceso de ‘jefes’ supone un enorme lastre cuando las decisiones que no deberían llevar más de unas horas o días, se convierten en paseos de meses en los que perdemos cualquier tipo de ventaja y nos obliga a ir siempre a remolque.

O cuando dificultan que las decisiones y políticas de empresa, se difundan con la suficiente rapidez y claridad a todos.

Además las enormes jerarquías añaden más opacidad, generan más departamentos estancos y son confusas para el resto de trabajadores que cuando miran hacia arriba solo ven un montón de jefes que en lugar de ser aliados se convierten en escollos que salvar.

Una estructura más plana, donde se reduzca el número de jefes pero se permita que emerjan más líderes, es mucho más cómoda para los trabajadores y más efectiva para la dirección.

 

Enchufismo.

Seamos claros, pese a que muchas empresas hayan intentado tomar medidas, el enchufismo sigue estando a la orden del día.

Seguro que muchos podríamos explicar casos claros en el día a día de nuestro trabajo, donde familiares de algún jefe o ese ‘colega’ se ven continuamente beneficiados desde arriba, hagan lo que hagan (o lo que es peor, aunque no hagan nada productivo).

La primera consecuencia es el malestar entre los trabajadores, que tienen que soportar al enchufado de turno y ver cómo promociona mientras ellos siguen estancados.

Luego están los errores cometidos por personas que ostentan puestos a los que han accedido sin estar preparados, que además suelen repetir en sus errores al sentirse protegidos desde arriba, que acarrean costes extras por planificaciones no cumplidas o cumplidas con deficiencias importantes.

Aunque para mí el peor es que mata cualquier tipo de iniciativa en el resto, que o bien terminan marchándose o bien se acomodan a lo que hay tras perder cualquier ilusión de progresión.

Por ello, es importante que una empresa se base en la meritocracia, recompensando los esfuerzos y méritos individuales y de grupos, para conseguir una mayor implicación en el trabajo diario.

#AOS2K15

CH-K8e4WwAAR0ws (2)

Los pasados 19 y 20 de Junio estuve de nuevo en la AOS. Esta vez se celebró en Gijón, una ciudad preciosa que no os voy a descubrir ahora.
No elegí el alojamiento oficial de la organización (camping de Deva) por problemas logísticos y me decanté por uno de los hoteles con los la organización nos ofrecía descuentos, el Hotel Asturias. Fue un gran acierto, el Hotel tiene una ubicación magnifica, impresionante, quería decirlo pero no me enrollo mas, vamos a lío.

Que es una AOS (Agile Open Space)
Un open space es un evento auto organizado por los asistentes a la misma. Básicamente: No hay agenda, la agenda se hace al inicio de cada día de AOS. Tampoco hay propuestas previas, las propuestas se presentan al inicio de cada día y se eligen por los asistentes. Si queréis una explicación mas profunda podéis verlo en la pagina de la organización

Si ya lo habéis leído, solo os comento una pequeña reflexión: De una AOS te llevarás lo que quieras llevar, depende de tí y para aprovechar una AOS, hay que ir con las pilas puestas, es un evento muy exigente y hacer de «mariposa» es mas que necesario para poder aguantar el ritmo (buscad «abeja, mariposa y open space»).

Porque mola una AOS
En una AOS lo más habitual es tener debates muy abiertos, con mucha libertad para participar, para aportar y poder recoger otros puntos de vista y experiencias. Aunque puede haber reuniones unidireccionales, la gran mayoría son mesas redondas.

Una de las cosas que más valoro es que recoges muchas experiencias de verdad, no de libro. Casos de uso de agile en entorno reales y duros como la vida misma. En otro tipo de reuniones suele haber mucha teoría y además, todo está muy preparado. El ponente prácticamente está pasando un examen sobre lo que cuenta, no te tienes que preocupar de ser «correcto», solo de aportar y recoger todo lo posible.

Algunas reuniones a las que fui
SAFe
No quiero acercarme a los frameworks y métodos en general para escalar agile que están saliendo en los últimos años. Tengo mis razones para no hacerlo pero no podía dejar pasar la oportunidad de tener un debate al respecto y no me arrepentí. El debate estuvo genial, intenso, con gente que está en el día a día usando SAFe y que nos contó como lo están aplicando. Me lleve una primera impresión de las soluciones que SAFe intenta aplicar a los problemas que encuentras al querer escalar. Fue una de la reuniones más interesantes (para mí, claro).

AARRR + story mapping
Fui a la AOS en tren desde Madrid. Son 5 horas y media pero no me importa porque me encanta el tren. Además me da la oportunidad de ir viendo vídeos (previamente descargados, lo de la wifi es ciencia ficción) que tengo atrasados desde hace tiempo.

Henrik Kniberg at LKCE14

 

Precisamente uno de los que más me ha gustado últimamente es la keynote de Henrik Kniberg en la pasada ALE , sobre el «entregable» de cada spring, en el que hablaba, entre otras cosas, de las métricas pirata.

Por eso, en cuanto se planteó una charla sobre AARRR e story mapping no me lo pensé ni un momento, estaba muy arriba en mi lista.
La charla no me defraudo, una buena explicación de como complementar un story mapping con técnicas AARRR para darle valor (la medida del valor) a los elementos planificados.
Siempre hablamos de priorizar las historias a planificar en el spring por su valor (de negocio) pero, como se consigue saber esa valoración? Intuición? Inspiración divina? Lo fácil que sea o chulo que parezca? Encuestas a usuario? Esta charla me clarifico formas de encauzar esas decisiones.
#noprojects
#noproject es otra de las corrientes que hay por la comunidad, igual que #noestimates y otras. Que es un proyecto? Desde pequeños nos han enseñado que para hacer un proyecto necesitamos un alcance + un presupuesto (recurso) + un deadline. No sé de qué mágica forma cumplir con scope, budget y fecha asegura reportar un beneficio a nuestro cliente pero en cualquier caso la verdad es que esto cuadra muy mal con el desarrollo de software.

PMI define un proyecto como un esfuerzo encaminado a conseguir un objetivo en una fecha determinada. (Yo no creo que tenga un fin definido y lo del principio, podríamos discutir mucho cuando empieza un proyecto). Es necesario un alcance? No se puede conseguir el objetivo mejor con sucesivas entregas? Tiene fin un proyecto software? Mucho que discutir ahí, desde que un alcance no se conoce (caminante no hay camino…) hasta que el único proyecto sin cambios es un proyecto que no se usa por nadie.

Equipos desorganizados
Otra de las charlas que me impactó fue la relacionada con equipos desorganizados . Realmente debe haber un «equipo»? Es el equipo la forma ideal de trabajar? Es lógico que los proyectos te «toquen»? No es más lógico que tú elijas a que proyectos te apuntas? Y es más, con qué nivel de compromiso te apuntas, no siempre tienes la misma disposición, somos personas con vida en el trabajo y fuera de él, con altibajos no deseados y altibajos deseados. No es más lógico una forma de trabajo estilo freelance?. Mucho en lo que pensar porque la verdad es que la uniformización en la forma de trabajar puede dar una imagen de orden y eficiencia pero no es natural que todos hagamos las cosas de la misma forma todo el tiempo….
Una parte muy positiva que me llevo de la charla es cuestionarlo todo, cuestionar en que nos basamos para pensar que hay que hacer las cosas como las hacemos. La charla fue genial, muy abierta y con muchas opiniones.

Fracaso Agile
En esta reunión me lleve uno de los problemas que cada vez más común, en el afán de ser agiles, estamos adoptando las técnicas pero no los principios y valores.

Agile Chasm

http://cmforagile.blogspot.com.es/2015/04/have-you-crossed-agile-chasm.html

Se está vaciando de contenido. Estamos cayendo por el precipicio? Me recuerda a algo que ocurre mucho con las matemáticas, cuando ante un problema el niño al que estas intentando enseñar a pensar cómo resolver te pregunta «pero, es de sumar o de restar». Aplicando solo el método de resolución no vamos a saber resolver el problema.

Otras que no pude ir
PopcornFlow
Una de las que no pude asistir fue una charla sobre una experiencia usando PopcornFlow. Cosa de la AOS y de no poder estar en varios sitios a la vez. Da la casualidad que en el tren venia viendo un vídeo de Claudio Perrone sobre A3 Thinking y PopcornFlow y llegue a Gijón justo antes de empezar con PopcornFlow, con lo que no sabía de qué iba.

Evolve or die_ A3 thinking and popcorn flow in action – Claudio Perrone at LKCE1

En el viaje de vuelta terminé el vídeo y la verdad es que tiene una pinta fantástica y queda anotado en mi backlog buscar experiencias usándolo.

#NoEstimates
Otra a la que no pude ir… Esta tengo muy clara la «teoría» y estoy totalmente de acuerdo con la filosofía que hay tras ello, pero quiero recoger como se usa en proyectos de verdad… Al backlog…

 

Equipo AOS
Desde aquí quiero trasmitir mi enorme agradecimiento al equipo organizador de la AOS. Cuando piensas en la cantidad de curro y de ilusión que hay que echar para organizar algo como esto, alucinas. Muchas gracias por vuestro esfuerzo y dedicación, nos hicisteis disfrutar de una AOS genial.
equipo aos

Disclaimer
Este articulo no pretende ser una valoración y ni siquiera una descripción de las charlas que hubo, el contenido fue mucho mas amplio y las discusiones mucho mas ricas de lo que soy capaz de poner y además, sobre la AOS hay tantas conclusiones como personas asistieron, cada cual se he llevado la suya. Solo representa una parte de lo que yo me he llevado.

Ah tambien me he llevado esta foto:

IMG_20150618_143153

Youtube API – How to copy the WatchLater List

Disclaimer

All the code here has been tested for 5 or 10 minutes… Use at your own risk. This is intended to be only a draft, a demo of the Youtube API possibilities and it is offered without any warranty.

 

OMG, It is written in English…

This post is going to be written in English. I must practice my English and write this will be a good way. So let it go…

 

Why do you want to copy the Watch Later List?

(don’t read this, there is no code here, continue below)  

When I code for pleasure, out of the office, at home or sometimes, on a hotel room, I have a particular way to do it. Some people likes to hear classical music, some prefer video games BSOs, some others totally silence… I like to see youtube music videos. Actually, most of the time, I don’t look at them, I only hear them but I like the way I can made a music selection on youtube. Let’s me explain it…

Before I begin to code, I do a selection of videos. The easy way of doing a selection is to add then to the “watch later” playlist. The selection last for a few days and I made a new one, normally because I want to hear a different kind of music (You know, sometime you prefer POP, sometimes Rock, sometimes games BSO…). But I don’t want to lose the old selection so I need to save it.

In the past you can do it on YouTube, you can re-organize your watch later list and copy selected videos to other list. But this is not more possible.
Last saturday evening I was very upset for this little problem so I google a little until find the youtube info API. And this article is the result. Now I can do that and a few things more…

 

How to do it

(if you don’t want to read more, you would prefer go to the github repository directly: https://github.com/sbgermanm/youtubeV2)

1. We need a google api client ID

1.1 Go to google api console: https://console.developers.google.com/

1.2 Create a new project

Crear proyecto

1.3 Activate youtube data api

enable api2

1.4 Create new client ID. Here you can take the data for the file client_secrets.json

create client id

client id created
1.5 Fill in the consent screen

consent screen
1.6 You are done

 

Let’s do it

Now that you can use the youtube api, let’s go make an application:

2. Resources

To understand how the API works, there are three importants helps from google:
2.1 The introduction to how the API works: https://developers.google.com/youtube/v3/getting-started
2.2 The API reference: https://developers.google.com/youtube/v3/docs/, where you can see the methods, the resource json structure (to figure out where you can get the data), the diferents resouce propoerties and some samples.
2.3 The API explorer: https://developers.google.com/apis-explorer/#p/youtube/v3/ a very useful resource to try the API. Here you can use all the api, try with different parameters and see the json request and response. It’s very important to know that you can limit the response of the api on several ways. You can read it in the first resource and you can interactively try it in this resource to make sure that you get what you want and only that. For example, you can easily compose the «field» parameter of the API.

3. The Code

As a line of code is better than 1 hundred words of comments, let’s code:

3.1 The pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>es.sebas</groupId>
    <artifactId>youtube2</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>jar</packaging>

    <repositories>
        <repository>
            <id>google-api-services</id>
            <url>http://google-api-client-libraries.appspot.com/mavenrepo</url>
        </repository>
    </repositories>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.youtube.version>v3-rev91-1.17.0-rc</project.youtube.version>
        <project.http.version>1.19.0</project.http.version>
        <project.oauth.version>1.19.0</project.oauth.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>
    <dependencies>

        <!-- YouTube Data V3 support -->
        <dependency>
            <groupId>com.google.apis</groupId>
            <artifactId>google-api-services-youtube</artifactId>
            <version>${project.youtube.version}</version>
        </dependency>

        <dependency>
            <groupId>com.google.http-client</groupId>
            <artifactId>google-http-client-jackson2</artifactId>
            <version>${project.http.version}</version>
        </dependency>

        <dependency>
            <groupId>com.google.oauth-client</groupId>
            <artifactId>google-oauth-client-jetty</artifactId>
            <version>${project.oauth.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Forces Maven to use Java 1.6 -->
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument></compilerArgument>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <name>youtube2</name>
</project>

 

3.2 The methods used in this function
3.2.1 Authorize

public static Credential authorize() throws IOException {

        List<String> scopes = Arrays.asList("https://www.googleapis.com/auth/youtube");

        Reader reader = new InputStreamReader(PlayListTools.class.getResourceAsStream("/client_secrets.json"));
        // Load client secrets.
        GoogleClientSecrets clientSecrets
                = GoogleClientSecrets.load(
                        JSON_FACTORY,
                        reader);

        FileDataStoreFactory fileDataStoreFactory = new FileDataStoreFactory(new File(System.getProperty("user.home") + "/" + CREDENTIALS_DIRECTORY));
        DataStore<StoredCredential> datastore = fileDataStoreFactory.getDataStore("youtubesebas");

        // Set up authorization code flow.
        GoogleAuthorizationCodeFlow flow
                = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT,
                        JSON_FACTORY,
                        clientSecrets,
                        scopes)
                .setCredentialDataStore(datastore)
                .build();

        // Build the local server and bind it to port 9000
        LocalServerReceiver localReceiver = new LocalServerReceiver.Builder().setPort(8080).build();

        // Authorize.
        return new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user");
}

and the credentials for the authorization client_secrets.json (put here the data you get on section 1.4)

{
 "installed": {
 "client_id": "Enter your client id here",
 "client_secret": "Enter your client secret here"
 }
}

 

3.2.2 Recover all watch later items

public static List<PlaylistItem> getAllWatchLaterItems(Credential credential) {

        String wlPlaylistId = getWlID(credential);
        System.out.println("WatchLaterId : " + wlPlaylistId);
        return getAllPlayListItems(credential, wlPlaylistId);
}

public static List<PlaylistItem> getAllPlayListItems(Credential credential, String playListID) {
        // List to store all PlaylistItem items associated with the uploadPlaylistId.
        ArrayList<PlaylistItem> playlistItemList = new ArrayList<PlaylistItem>();

        /*
         * Now that the user is authenticated, the app makes a channel list request to get the
         * authenticated user's channel. Returned with that data is the playlist id for the uploaded
         * videos. https://developers.google.com/youtube/v3/docs/channels/list
         */
        YouTube youtube = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), credential)
                .setApplicationName("youtube-sebas")
                .build();

        /*
         * Now that we have the playlist id for your uploads, we will request the playlistItems
         * associated with that playlist id, so we can get information on each video uploaded. This
         * is the template for the list call. We call it multiple times in the do while loop below
         * (only changing the nextToken to get all the videos).
         * https://developers.google.com/youtube/v3/docs/playlistitems/list
         */
        YouTube.PlaylistItems.List playlistItemRequest;
        try {
            playlistItemRequest = youtube.playlistItems().list("id,contentDetails,snippet");
            playlistItemRequest.setPlaylistId(playListID);

            // This limits the results to only the data we need and makes things more efficient.
            playlistItemRequest.setFields(
                    "items(id,contentDetails/videoId,snippet/title),nextPageToken,pageInfo");

            String nextToken = "";

            // Loops over all search page results returned for the uploadPlaylistId.
            do {
                playlistItemRequest.setPageToken(nextToken);
                PlaylistItemListResponse playlistItemResult = playlistItemRequest.execute();

                playlistItemList.addAll(playlistItemResult.getItems());

                nextToken = playlistItemResult.getNextPageToken();
            } while (nextToken != null);

        } catch (IOException ex) {
            Logger.getLogger(PlayListTools.class.getName()).log(Level.SEVERE, null, ex);
        }

        return playlistItemList;
}

 

3.2.3 Insert a new playList

public static String insertPlaylist(String playlistTitle, String playlistDesc, Credential credential) throws IOException {

        /*
         * We need to first create the parts of the Playlist before the playlist itself.  Here we are
         * creating the PlaylistSnippet and adding the required data.
         */
        PlaylistSnippet playlistSnippet = new PlaylistSnippet();
        playlistSnippet.setTitle(playlistTitle);
        playlistSnippet.setDescription(playlistDesc);

        // Here we set the privacy status (required).
        PlaylistStatus playlistStatus = new PlaylistStatus();
        playlistStatus.setPrivacyStatus("private");

        /*
         * Now that we have all the required objects, we can create the Playlist itself and assign the
         * snippet and status objects from above.
         */
        Playlist youTubePlaylist = new Playlist();
        youTubePlaylist.setSnippet(playlistSnippet);
        youTubePlaylist.setStatus(playlistStatus);

        /*
         * This is the object that will actually do the insert request and return the result.  The
         * first argument tells the API what to return when a successful insert has been executed.  In
         * this case, we want the snippet and contentDetails info.  The second argument is the playlist
         * we wish to insert.
         */
        // YouTube object used to make all API requests.
        YouTube youtube = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), credential)
                .setApplicationName("youtube-sebas")
                .build();

        YouTube.Playlists.Insert playlistInsertCommand
                = youtube.playlists().insert("snippet,status", youTubePlaylist);
        Playlist playlistInserted = playlistInsertCommand.execute();

        // Pretty print results.
        System.out.println("New Playlist name: " + playlistInserted.getSnippet().getTitle());
        System.out.println(" - Privacy: " + playlistInserted.getStatus().getPrivacyStatus());
        System.out.println(" - Description: " + playlistInserted.getSnippet().getDescription());
        System.out.println(" - Channel: " + playlistInserted.getSnippet().getChannelId() + "n");
        return playlistInserted.getId();

}

 

3.2.4 Insert the previously recovered items (the watch later items)

public static void insertPlaylistItems(Credential credential, String playlistId, List<PlaylistItem> playListItems) {

        for (PlaylistItem playlistItem : playListItems) {
            try {
                System.out.println("Inserting Video, ID=" + playlistItem.getContentDetails().getVideoId() + " with title: " + playlistItem.getSnippet().getTitle());
                insertPlaylistItem(credential, playlistId, playlistItem.getContentDetails().getVideoId(), playlistItem.getSnippet().getTitle());
            } catch (IOException ex) {
                Logger.getLogger(PlayListTools.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

}

private static String insertPlaylistItem(Credential credential, String playlistId, String videoId, String title) throws IOException {

        /*
         * The Resource type (video,playlist,channel) needs to be set along with the resource id. In
         * this case, we are setting the resource to a video id, since that makes sense for this
         * playlist.
         */
        ResourceId resourceId = new ResourceId();
        resourceId.setKind(RESOURCE_KIND_VIDEO);
        resourceId.setVideoId(videoId);

        /*
         * Here we set all the information required for the snippet section.  We also assign the
         * resource id from above to the snippet object.
         */
        PlaylistItemSnippet playlistItemSnippet = new PlaylistItemSnippet();
        playlistItemSnippet.setTitle(title);
        playlistItemSnippet.setPlaylistId(playlistId);
        playlistItemSnippet.setResourceId(resourceId);

        /*
         * Now that we have all the required objects, we can create the PlaylistItem itself and assign
         * the snippet object from above.
         */
        PlaylistItem playlistItem = new PlaylistItem();
        playlistItem.setSnippet(playlistItemSnippet);

        /*
         * This is the object that will actually do the insert request and return the result.  The
         * first argument tells the API what to return when a successful insert has been executed.  In
         * this case, we want the snippet and contentDetails info.  The second argument is the
         * playlistitem we wish to insert.
         */
        YouTube youtube = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), credential)
                .setApplicationName("youtube-sebas")
                .build();
        YouTube.PlaylistItems.Insert playlistItemsInsertCommand
                = youtube.playlistItems().insert("snippet,contentDetails", playlistItem);
        PlaylistItem returnedPlaylistItem = playlistItemsInsertCommand.execute();

        printPlayListItem(returnedPlaylistItem);

        return returnedPlaylistItem.getId();

}

 

3.2.5 Some globals…

 /**
 * Global instance of the HTTP transport.
 */
 private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();

 /**
 * Global instance of the JSON factory.
 */
 private static final JsonFactory JSON_FACTORY = new JacksonFactory();

/**
* Some constants...
*/
 private static final String RESOURCE_KIND_VIDEO = "youtube#video";
 private static final String CREDENTIALS_DIRECTORY = ".oauth-credentials";

 

3.2.6 The method that do the copy

public static void main(String[] args) {

        // Authorization.
        Credential credential = null;
        try {
            credential = PlayListTools.authorize();
        } catch (IOException ex) {
            Logger.getLogger(WacthLaterCopy.class.getName()).log(Level.SEVERE, null, ex);
        }

        List<PlaylistItem> wlPlayListItems = PlayListTools.getAllWatchLaterItems(credential);

        String playlistTitle = "Temporal Playlist " + Calendar.getInstance().getTime();
        String playlistDesc = "A private temporal playlist created with the YouTube API v3";
        String playlistId;
        try {
            playlistId = PlayListTools.insertPlaylist(playlistTitle, playlistDesc, credential);

            // If a valid playlist was created, adds a new playlistitem with a video to that playlist.
            PlayListTools.insertPlaylistItems(credential, playlistId, wlPlayListItems);
        } catch (IOException ex) {
            Logger.getLogger(WacthLaterCopy.class.getName()).log(Level.SEVERE, null, ex);
        }
}

 

3.2.7 The maven comand line to automate this

mvn exec:java -Dexec.mainClass=”es.sebas.youtube.WatChLaterCopy”

 

To be continued

Now we have the copy of the Watch Later List. In next post I will show :

  • How to Purge the Watch Later List
  • How to create a VideoLan List of the videos in our playLists

Write you later…