Merge pull request #5 from biconou/forPullRequests

Added podcasts feature
This commit is contained in:
Óscar García Amor 2016-04-01 13:26:29 +02:00
commit 21ec27fd3c
30 changed files with 973 additions and 0 deletions

View File

@ -57,6 +57,11 @@
a:configChanges="orientation|keyboardHidden"
a:label="@string/playlist.label"
a:launchMode="standard"/>
<activity
a:name=".activity.PodcastsActivity"
a:configChanges="orientation|keyboardHidden"
a:label="@string/podcasts.label"
a:launchMode="standard"/>
<activity
a:name=".activity.BookmarkActivity"
a:configChanges="orientation|keyboardHidden"/>

View File

@ -0,0 +1,85 @@
package org.moire.ultrasonic.Test.service;
import java.io.Reader;
import java.io.StringReader;
/**
* Created by rcocula on 11/03/2016.
*/
public class GetPodcastEpisodesTestReaderProvider {
private static String data = "<subsonic-response status=\"ok\" version=\"1.12.0\" xmlns=\"http://subsonic.org/restapi\">\n" +
" <podcasts>\n" +
" <channel id=\"0\" url=\"http://radiofrance-podcast.net/podcast09/rss_13183.xml\" title=\"La tribune des critiques de disques\" description=\"Sous la houlette de Jérémie Rousseau, d'éminents critiques musicaux écoutent à l'aveugle différentes versions d'une oeuvre du répertoire et la commentent\" status=\"completed\">\n" +
" <episode id=\"2551\" parent=\"42169\" isDir=\"false\" title=\"2ème Sonate, Op. 35 de Frédéric Chopin.\" album=\"2ème Sonate, Op. 35 de Frédéric Chopin.\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87140480\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5428\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-06.03.2016-ITEMA_20929680-0.mp3\" isVideo=\"false\" created=\"2016-03-06T21:13:09.000Z\" albumId=\"4089\" artistId=\"1457\" type=\"podcast\" streamId=\"54710\" description=\"durée : 01:30:16 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec la participation d'Elsa Fottorino, Stéphane Friédérich et Piotr Kaminski. - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-03-06T20:00:00.000Z\"/>\n" +
" <episode id=\"2513\" parent=\"42169\" isDir=\"false\" title=\"Harmonielehre de John Adams\" album=\"La tribune des critiques de disques\" coverArt=\"42169\" size=\"639\" contentType=\"audio/mpeg\" suffix=\"mp3\" path=\"La tribune des critiques de disques/13183-28.02.2016-ITEMA_20924164-0.mp3\" isVideo=\"false\" created=\"2016-02-28T21:38:56.000Z\" type=\"podcast\" streamId=\"54674\" description=\"durée : 01:30:27 - La tribune des critiques de disques - par : Jérémie Rousseau - Bertrand Dermoncourt, Classica - Emmanuelle Guiliani, La Croix - Jean-Charles Hoffelé, Diapason - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-02-28T20:00:00.000Z\"/>\n" +
" <episode id=\"2465\" parent=\"42169\" isDir=\"false\" title=\"Le Barbier de Séville (Acte I) de Gioachino Rossini\" album=\"Le Barbier de Séville (Acte I) de Gioachino Rossini\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87089280\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5424\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-21.02.2016-ITEMA_20918652-0.mp3\" isVideo=\"false\" created=\"2016-02-22T04:13:19.000Z\" albumId=\"3955\" artistId=\"1457\" type=\"podcast\" streamId=\"54629\" description=\"durée : 01:30:12 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Chantal Cazaux, Emmanuel Dupuy et Sylvain Fort - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-02-21T20:00:00.000Z\"/>\n" +
" <episode id=\"2432\" parent=\"42169\" isDir=\"false\" title=\"Suite en La de Jean-Philippe Rameau\" album=\"Suite en La de Jean-Philippe Rameau\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86632576\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5396\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-14.02.2016-ITEMA_20913147-0.mp3\" isVideo=\"false\" created=\"2016-02-16T22:16:23.000Z\" albumId=\"3929\" artistId=\"1457\" type=\"podcast\" streamId=\"54563\" description=\"durée : 01:29:44 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Elsa Fottorino, Piotr Kaminski, Philippe Venturini - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-02-14T20:00:00.000Z\"/>\n" +
" <episode id=\"2397\" parent=\"42169\" isDir=\"false\" title=\"La Valse de l'Empereur de Johann Strauss\" album=\"La Valse de l'Empereur de Johann Strauss\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87042176\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5421\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-07.02.2016-ITEMA_20907545-0.mp3\" isVideo=\"false\" created=\"2016-02-09T04:13:46.000Z\" albumId=\"3893\" artistId=\"1457\" type=\"podcast\" streamId=\"54491\" description=\"durée : 01:30:09 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Séverine Garnier, Emmanuelle Giuliani, Christian Merlin - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-02-07T20:00:00.000Z\"/>\n" +
" <episode id=\"2328\" parent=\"42169\" isDir=\"false\" title=\"Concerto pour piano n° 22 en mi bémol majeur K 482 de Wolfgang Amadeus Mozart\" album=\"Concerto pour piano n° 22 en mi bémol majeur K 482 de Wolfgang Amadeus Mozart\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87261312\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5435\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-31.01.2016-ITEMA_20901964-00.mp3\" isVideo=\"false\" created=\"2016-02-04T04:13:08.000Z\" albumId=\"3872\" artistId=\"1457\" type=\"podcast\" streamId=\"54400\" description=\"durée : 01:30:23 - La tribune des critiques de disques - par : Jérémie Rousseau - Sylvain Fort, Forum Opéra - Elsa Fottorino, Revue Pianiste - Christian Merlin, Le Figaro - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-01-31T20:00:00.000Z\"/>\n" +
" <episode id=\"2321\" parent=\"42169\" isDir=\"false\" title=\"Concerto pour piano n° 22 en mi bémol majeur K 482 de Wolfgang Amadeus Mozart\" album=\"Concerto pour piano n° 22 en mi bémol majeur K 482 de Wolfgang Amadeus Mozart\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87261312\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5435\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-31.01.2016-ITEMA_20901964-0.mp3\" isVideo=\"false\" created=\"2016-02-03T21:23:06.000Z\" albumId=\"3872\" artistId=\"1457\" type=\"podcast\" streamId=\"54385\" description=\"durée : 01:30:23 - La tribune des critiques de disques - par : Jérémie Rousseau - Sylvain Fort, Forum Opéra - Elsa Fottorino, Revue Pianiste - Christian Merlin, Le Figaro - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-01-31T20:00:00.000Z\"/>\n" +
" <episode id=\"2267\" parent=\"42169\" isDir=\"false\" title=\"Symphonie n° 2 &quot;Le Double&quot; d'Henri Dutilleux\" album=\"Symphonie n° 2 ''Le Double'' d'Henri Dutilleux\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86952064\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5416\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-24.01.2016-ITEMA_20896460-0.mp3\" isVideo=\"false\" created=\"2016-01-25T04:13:51.000Z\" albumId=\"3829\" artistId=\"1457\" type=\"podcast\" streamId=\"54245\" description=\"durée : 01:30:04 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Bertrand Dermoncourt, Emmanuelle Giuliani, Jean-Charles Hoffelé - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-01-24T20:00:00.000Z\"/>\n" +
" <episode id=\"2225\" parent=\"42169\" isDir=\"false\" title=\"Gymnopédies de Erik Satie\" album=\"Gymnopédies de Erik Satie\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86579328\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5392\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-17.01.2016-ITEMA_20890984-0.mp3\" isVideo=\"false\" created=\"2016-01-18T04:13:13.000Z\" albumId=\"3792\" artistId=\"1457\" type=\"podcast\" streamId=\"54089\" description=\"durée : 01:29:40 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Bertrand Dermoncourt, Elsa Fottorino, Antoine Mignon - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-01-17T20:00:00.000Z\"/>\n" +
" <episode id=\"2189\" parent=\"42169\" isDir=\"false\" title=\"Quatuor n° 13 en la mineur, D. 804 (op. 29) 'Rosamunde&quot; de Franz Schubert\" album=\"Quatuor n° 13 en la mineur, D. 804 (op. 29) 'Rosamunde'' de Franz Schubert\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86990976\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5418\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-10.01.2016-ITEMA_20885378-0.mp3\" isVideo=\"false\" created=\"2016-01-11T04:14:15.000Z\" albumId=\"3764\" artistId=\"1457\" type=\"podcast\" streamId=\"53982\" description=\"durée : 01:30:06 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Jérémie Cahen, Piotr Kaminski, Philippe Venturini - réalisé par : Marie Grout\" status=\"completed\" publishDate=\"2016-01-10T20:00:00.000Z\"/>\n" +
" <episode id=\"2146\" parent=\"42169\" isDir=\"false\" title=\"Les Quatre Derniers Lieder de Richard Strauss\" album=\"Les Quatre Derniers Lieder de Richard Strauss\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87040128\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5421\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-03.01.2016-ITEMA_20879946-0.mp3\" isVideo=\"false\" created=\"2016-01-04T04:12:55.000Z\" albumId=\"3735\" artistId=\"1457\" type=\"podcast\" streamId=\"53939\" description=\"durée : 01:30:09 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Christian Merlin, Emmanuelle Giuliani et Eric Taver - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2016-01-03T20:00:00.000Z\"/>\n" +
" <episode id=\"2108\" parent=\"42169\" isDir=\"false\" title=\"&quot;Une petite musique de nuit&quot;, Sérénade n° 13 en sol Majeur de Wolfgang-Amadeus Mozart\" album=\"''Une petite musique de nuit'', Sérénade n° 13 en sol Majeur de Wolfgang-Amadeus Mozart\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86259840\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5372\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-27.12.2015-ITEMA_20874498-0.mp3\" isVideo=\"false\" created=\"2015-12-28T04:12:57.000Z\" albumId=\"3708\" artistId=\"1457\" type=\"podcast\" streamId=\"53865\" description=\"durée : 01:29:20 - La tribune des critiques de disques - par : Jérémie Rousseau - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-12-27T20:00:00.000Z\"/>\n" +
" <episode id=\"2070\" parent=\"42169\" isDir=\"false\" title=\"La Cantate BWV 61 &quot;Nun komm, der Heiden Heiland&quot; de Jean-Sébastien Bach\" album=\"La Cantate BWV 61 ''Nun komm, der Heiden Heiland'' de Jean-Sébastien Bach\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87079040\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5424\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-20.12.2015-ITEMA_20868893-0.mp3\" isVideo=\"false\" created=\"2015-12-21T04:13:10.000Z\" albumId=\"3670\" artistId=\"1457\" type=\"podcast\" streamId=\"53761\" description=\"durée : 01:30:12 - La tribune des critiques de disques - par : Jérémie Rousseau - Emission enregistrée en public jeudi 10 décembre au studio 109 à 19h. Avec la participation d'Emmanuel Dupuy, Séverine Garnier et Emmanuelle Giuliani. - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-12-20T20:00:00.000Z\"/>\n" +
" <episode id=\"2025\" parent=\"42169\" isDir=\"false\" title=\"Les Notations pour piano de Pierre Boulez\" album=\"Les Notations pour piano de Pierre Boulez\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86775936\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5405\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-13.12.2015-ITEMA_20863386-0.mp3\" isVideo=\"false\" created=\"2015-12-14T04:13:16.000Z\" albumId=\"3626\" artistId=\"1457\" type=\"podcast\" streamId=\"53522\" description=\"durée : 01:29:53 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Jérémie Bigorie, Jérémie Cahen et Christian Merlin. - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-12-13T20:00:00.000Z\"/>\n" +
" <episode id=\"1983\" parent=\"42169\" isDir=\"false\" title=\"Les Scènes d'enfants op.15 de Robert Schumann\" album=\"Les Scènes d'enfants op.15 de Robert Schumann\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87011456\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5419\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-06.12.2015-ITEMA_20857958-0.mp3\" isVideo=\"false\" created=\"2015-12-07T04:12:55.000Z\" albumId=\"3593\" artistId=\"1457\" type=\"podcast\" streamId=\"53437\" description=\"durée : 01:30:07 - La tribune des critiques de disques - par : Jérémie Rousseau - avec Elsa Fottorino, Jean-Charles Hoffelé et Antoine Mignon. - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-12-06T20:00:00.000Z\"/>\n" +
" <episode id=\"1937\" parent=\"42169\" isDir=\"false\" title=\"Concerto pour piano n°1 en mi bémol Majeur de Franz Liszt\" album=\"Concerto pour piano n°1 en mi bémol Majeur de Franz Liszt\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86730880\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5402\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-29.11.2015-ITEMA_20852326-0.mp3\" isVideo=\"false\" created=\"2015-11-30T04:12:27.000Z\" albumId=\"3570\" artistId=\"1457\" type=\"podcast\" streamId=\"53388\" description=\"durée : 01:29:50 - La tribune des critiques de disques - par : Jérémie Rousseau - Emission enregistrée le jeudi 19 novembre au studio 109 à 19h. Avec la participation d'Elsa Fottorino, Stéphane Friédérich et Sylvain Fort. - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-11-29T20:00:00.000Z\"/>\n" +
" <episode id=\"1810\" parent=\"42169\" isDir=\"false\" title=\"Le Concerto pour deux mandolines en sol Majeur RV 532 de Vivaldi\" album=\"Le Concerto pour deux mandolines en sol Majeur RV 532 de Vivaldi\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86470784\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5386\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-15.11.2015-ITEMA_20841620-0.mp3\" isVideo=\"false\" created=\"2015-11-16T04:12:27.000Z\" albumId=\"3512\" artistId=\"1457\" type=\"podcast\" streamId=\"53214\" description=\"durée : 01:29:34 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Bigorie, Emmanuelle Giuliani, Piotr Kaminski - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-11-15T20:00:00.000Z\"/>\n" +
" <episode id=\"1778\" parent=\"42169\" isDir=\"false\" title=\"Les Contes d'Hoffmann d'Offenbach (acte II)\" album=\"Les Contes d'Hoffmann d'Offenbach (acte II)\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87195776\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5431\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-08.11.2015-ITEMA_20836265-0.mp3\" isVideo=\"false\" created=\"2015-11-09T04:12:48.000Z\" albumId=\"3478\" artistId=\"1457\" type=\"podcast\" streamId=\"53159\" description=\"durée : 01:30:19 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Chantal Cazaux, Emmanuel Dupuy, Sylvain Fort - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-11-08T20:00:00.000Z\"/>\n" +
" <episode id=\"1721\" parent=\"42169\" isDir=\"false\" title=\"Symphonie n°7 de Bruckner\" album=\"Symphonie n°7 de Bruckner\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87429248\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5446\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-01.11.2015-ITEMA_20830962-00.mp3\" isVideo=\"false\" created=\"2015-11-03T21:57:28.000Z\" albumId=\"3441\" artistId=\"1457\" type=\"podcast\" streamId=\"51952\" description=\"durée : 01:30:34 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Cahen, Christian Merlin, Philippe Venturini - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-11-01T20:00:00.000Z\"/>\n" +
" <episode id=\"1658\" parent=\"42169\" isDir=\"false\" title=\"Jean Sebastien Bach : Partita n°1 en si bémol Majeur BWV 825\" album=\"Jean Sebastien Bach : Partita n°1 en si bémol Majeur BWV 825\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86999168\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5419\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-25.10.2015-ITEMA_20825686-0.mp3\" isVideo=\"false\" created=\"2015-10-26T04:09:47.000Z\" albumId=\"3328\" artistId=\"1457\" type=\"podcast\" streamId=\"50164\" description=\"durée : 01:30:07 - La tribune des critiques de disques - par : Jérémie Rousseau - réalisé par : Sylvain Richard\" status=\"completed\" publishDate=\"2015-10-25T20:00:00.000Z\"/>\n" +
" <episode id=\"1618\" parent=\"42169\" isDir=\"false\" title=\"Tchaïkovsky : Sérénade pour cordes\" album=\"Tchaïkovsky : Sérénade pour cordes\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87337088\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5440\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-18.10.2015-ITEMA_20820416-0.mp3\" isVideo=\"false\" created=\"2015-10-19T03:10:05.000Z\" albumId=\"3327\" artistId=\"1457\" type=\"podcast\" streamId=\"49791\" description=\"durée : 01:30:28 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jean-Charles Hoffelé, Antoine Mignon, Eric Taver - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-10-18T19:00:00.000Z\"/>\n" +
" <episode id=\"1581\" parent=\"42169\" isDir=\"false\" title=\"Arvo Pärt : Magnificat\" album=\"Arvo Pärt : Magnificat\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86837376\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5408\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-11.10.2015-ITEMA_20815299-0.mp3\" isVideo=\"false\" created=\"2015-10-12T03:10:01.000Z\" albumId=\"3326\" artistId=\"1457\" type=\"podcast\" streamId=\"49731\" description=\"durée : 01:29:57 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Bertrand Dermoncourt, Séverine Garnier, Emmanuelle Giuliani - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-10-11T19:00:00.000Z\"/>\n" +
" <episode id=\"1538\" parent=\"42169\" isDir=\"false\" title=\"Scherzos de Chopin\" album=\"Scherzos de Chopin\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87048320\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5422\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-04.10.2015-ITEMA_20810281-0.mp3\" isVideo=\"false\" created=\"2015-10-04T20:20:32.000Z\" albumId=\"3325\" artistId=\"1457\" type=\"podcast\" streamId=\"49693\" description=\"durée : 01:30:10 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Elsa Fottorino, Sylvain Fort, Christian Merlin - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-10-04T19:00:00.000Z\"/>\n" +
" <episode id=\"1502\" parent=\"42169\" isDir=\"false\" title=\"Haendel : Dixit Dominus\" album=\"Haendel : Dixit Dominus\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87736448\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5465\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-27.09.2015-ITEMA_20805338-0.mp3\" isVideo=\"false\" created=\"2015-09-28T18:31:27.000Z\" albumId=\"3324\" artistId=\"1457\" type=\"podcast\" streamId=\"49634\" description=\"durée : 01:30:53 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Chantal Cazaux, Emmanuel Dupuy, Emmanuelle Giuliani - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-09-27T19:00:00.000Z\"/>\n" +
" <episode id=\"1458\" parent=\"42169\" isDir=\"false\" title=\"Beethoven : Sonate n°23 &quot;Appassionata&quot;\" album=\"Beethoven : Sonate n°23 ''Appassionata''\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86859904\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5410\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-20.09.2015-ITEMA_20800368-0.mp3\" isVideo=\"false\" created=\"2015-09-21T03:14:46.000Z\" albumId=\"3300\" artistId=\"1457\" type=\"podcast\" streamId=\"49559\" description=\"durée : 01:29:58 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Elsa Fottorino, Christian Merlin, Antoine Mignon - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-09-20T19:00:00.000Z\"/>\n" +
" <episode id=\"1417\" parent=\"42169\" isDir=\"false\" title=\"Verdi : Le Trouvère (acte II)\" album=\"Verdi : Le Trouvère (acte II)\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87050368\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5422\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-13.09.2015-ITEMA_20795506-0.mp3\" isVideo=\"false\" created=\"2015-09-14T03:16:50.000Z\" albumId=\"3269\" artistId=\"1457\" type=\"podcast\" streamId=\"49504\" description=\"durée : 01:30:10 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Bigorie, Chantal Cazaux, Piotr Kaminski - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-09-13T19:00:00.000Z\"/>\n" +
" <episode id=\"860\" parent=\"42169\" isDir=\"false\" title=\"Concerto pour clarinette en la majeur K 622 (1791) de Wolfgang-Amadeus Mozart\" album=\"Concerto pour clarinette en la majeur K 622 (1791) de Wolfgang-Amadeus Mozart\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86745216\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5403\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-06.09.2015-ITEMA_20790942-0.mp3\" isVideo=\"false\" created=\"2015-09-07T03:17:51.000Z\" albumId=\"3253\" artistId=\"1457\" type=\"podcast\" streamId=\"49461\" description=\"durée : 01:29:51 - La tribune des critiques de disques - par : Jérémie Rousseau - Stéphane Friédérich, Pianiste - Emmanuelle Giuliani, La Croix - Antoine Mignon, Classica - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-09-06T19:00:00.000Z\"/>\n" +
" <episode id=\"709\" parent=\"42169\" isDir=\"false\" title=\"Gnossiennes de Satie\" album=\"Gnossiennes de Satie\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86691968\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5399\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-30.08.2015-ITEMA_20787504-00.mp3\" isVideo=\"false\" created=\"2015-09-01T19:28:47.000Z\" albumId=\"2615\" artistId=\"1457\" type=\"podcast\" streamId=\"45554\" description=\"durée : 01:29:47 - La tribune des critiques de disques - par : Jérémie Rousseau - thème de la semaine : Rediffusion du 22 février 2015 - avec Christian Merlin, Bertrand Dermoncourt et Elsa Fottorino - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-08-30T19:00:00.000Z\"/>\n" +
" <episode id=\"710\" isDir=\"false\" title=\"Parsifal de Wagner, acte III\" description=\"durée : 01:29:46 - La tribune des critiques de disques - par : Jérémie Rousseau - thème de la semaine : Rediffusion du 23 novembre 2014 - Avec Chantal Cazaux, Emmanuel Dupuy, Christian Merlin - réalisé par : Géraldine Prutner\" status=\"skipped\" publishDate=\"2015-08-23T19:00:00.000Z\"/>\n" +
" <episode id=\"711\" isDir=\"false\" title=\"Sonate opus 111 de Beethoven\" description=\"durée : 01:29:43 - La tribune des critiques de disques - par : Jérémie Rousseau - thème de la semaine : Rediffusion du 11 janvier 2015 - Avec Elsa Fottorino, Christian Merlin, Antoine Mignon - réalisé par : Géraldine Prutner\" status=\"skipped\" publishDate=\"2015-08-16T19:00:00.000Z\"/>\n" +
" <episode id=\"712\" isDir=\"false\" title=\"Concerto pour piano &quot; Jeunehomme &quot; de Mozart\" description=\"durée : 01:29:42 - La tribune des critiques de disques - par : Jérémie Rousseau - thème de la semaine : Rediffusion du 1er mars 2015 - Concerto pour piano &amp;quot; Jeunehomme &amp;quot; de Mozart - réalisé par : Géraldine Prutner\" status=\"skipped\" publishDate=\"2015-08-09T19:00:00.000Z\"/>\n" +
" <episode id=\"713\" isDir=\"false\" title=\"Neuvième Symphonie de Beethoven\" description=\"durée : 01:29:40 - La tribune des critiques de disques - par : Jérémie Rousseau - thème de la semaine : Rediffusion du 26 octobre 2014 - Avec Stéphane Friederich , Emmanuelle Giuliani et Philippe Venturini - réalisé par : Cyrielle Weber\" status=\"skipped\" publishDate=\"2015-08-02T19:00:00.000Z\"/>\n" +
" <episode id=\"714\" isDir=\"false\" title=\"Dans les brumes de Leos Janacek\" description=\"durée : 01:29:54 - La tribune des critiques de disques - par : Jérémie Rousseau - thème de la semaine : Rediffusion du 2 novembre 2014 - Avec Bertrand Dermoncourt, Elsa Fottorino et Piotr Kaminski - réalisé par : Géraldine Prutner\" status=\"skipped\" publishDate=\"2015-07-26T19:00:00.000Z\"/>\n" +
" <episode id=\"715\" isDir=\"false\" title=\"&quot;Le Beau Danube Bleu&quot; de Johann Strauss\" description=\"durée : 01:29:41 - La tribune des critiques de disques - par : Jérémie Rousseau - thème de la semaine : Rediffusion - avec Emmanuelle Giuliani, Christian Merlin et Bertrand Dermoncourt - réalisé par : Géraldine Prutner\" status=\"skipped\" publishDate=\"2015-07-19T19:00:00.000Z\"/>\n" +
" <episode id=\"716\" isDir=\"false\" title=\"Gloria de Vivaldi\" description=\"durée : 01:29:44 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Bigorie, Classica, Chantal Cazaux, musicologue et enseignante et Philippe Venturini, Les Echos et Classica - réalisé par : Géraldine Prutner\" status=\"skipped\" publishDate=\"2015-07-12T19:00:00.000Z\"/>\n" +
" <episode id=\"698\" parent=\"42169\" isDir=\"false\" title=\"Symphonie n°8 de Chostakovitch\" album=\"Symphonie n°8 de Chostakovitch\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86915200\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5413\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-28.06.2015-ITEMA_20771947-0.mp3\" isVideo=\"false\" created=\"2015-06-28T22:18:40.000Z\" albumId=\"2614\" artistId=\"1456\" type=\"podcast\" streamId=\"44999\" description=\"durée : 01:30:01 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Bertrand Dermoncourt, Emmanuelle Giuliani, Xavier Lacavalerie - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-06-28T19:00:00.000Z\"/>\n" +
" <episode id=\"681\" parent=\"42169\" isDir=\"false\" title=\"Passion selon Saint Jean de Bach\" album=\"Passion selon Saint Jean de Bach\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86993024\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5418\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-21.06.2015-ITEMA_20769183-0.mp3\" isVideo=\"false\" created=\"2015-06-21T20:47:41.000Z\" albumId=\"2613\" artistId=\"1456\" type=\"podcast\" streamId=\"44877\" description=\"durée : 01:30:06 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Bigorie, Emmanuel Dupuy, Eric Taver\n" +
" - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-06-21T19:00:00.000Z\"/>\n" +
" <episode id=\"668\" parent=\"42169\" isDir=\"false\" title=\"Concerto pour violon de Sibelius\" album=\"Concerto pour violon de Sibelius\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86059136\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5360\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-14.06.2015-ITEMA_20766550-00.mp3\" isVideo=\"false\" created=\"2015-06-16T21:56:04.000Z\" albumId=\"2612\" artistId=\"1456\" type=\"podcast\" streamId=\"44869\" description=\"durée : 01:29:08 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Stéphane Friédérich, Jennifer Lesieur, Philippe Venturini - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-06-14T19:00:00.000Z\"/>\n" +
" <episode id=\"661\" parent=\"42169\" isDir=\"false\" title=\"Trio n°1 op. 49 de Mendelssohn\" album=\"Trio n°1 op. 49 de Mendelssohn\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86151296\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5366\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-07.06.2015-ITEMA_20763789-0.mp3\" isVideo=\"false\" created=\"2015-06-07T21:54:20.000Z\" albumId=\"2611\" artistId=\"1456\" type=\"podcast\" streamId=\"44850\" description=\"durée : 01:29:14 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jean-Charles Hoffelé, Antoine Mignon, Eric Taver - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-06-07T19:00:00.000Z\"/>\n" +
" <episode id=\"642\" parent=\"42169\" isDir=\"false\" title=\"Miroirs, de Maurice Ravel\" album=\"Miroirs, de Maurice Ravel\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86952064\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5416\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-31.05.2015-ITEMA_20761227-0.mp3\" isVideo=\"false\" created=\"2015-06-03T21:33:17.000Z\" albumId=\"2610\" artistId=\"1456\" type=\"podcast\" streamId=\"44727\" description=\"durée : 01:30:04 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Cahen, Stéphane Friédérich, Elsa Fottorino - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-05-31T19:00:00.000Z\"/>\n" +
" <episode id=\"643\" isDir=\"false\" title=\"La Walkyrie de Wagner, acte I\" description=\"durée : 01:30:06 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Chantal Cazaux, Emmanuel Dupuy, Christian Merlin - réalisé par : Cyrielle Weber\" status=\"skipped\" publishDate=\"2015-05-24T19:00:00.000Z\"/>\n" +
" <episode id=\"633\" parent=\"42169\" isDir=\"false\" title=\"Messe du Couronnement de Mozart\" album=\"Messe du Couronnement de Mozart\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86921344\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5414\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-17.05.2015-ITEMA_20756109-0.mp3\" isVideo=\"false\" created=\"2015-05-17T21:47:51.000Z\" albumId=\"2609\" artistId=\"1456\" type=\"podcast\" streamId=\"44636\" description=\"durée : 01:30:02 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Bertrand Dermoncourt (Classica), Emmanuelle Giuliani (La Croix) et Piotr Kaminski (Diapason). - réalisé par : Cyrielle Weber\" status=\"completed\" publishDate=\"2015-05-17T19:00:00.000Z\"/>\n" +
" <episode id=\"620\" parent=\"42169\" isDir=\"false\" title=\"Concerto pour piano n°2 de Rachmaninov\" album=\"Concerto pour piano n°2 de Rachmaninov\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86995072\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5418\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-10.05.2015-ITEMA_20753543-0.mp3\" isVideo=\"false\" created=\"2015-05-10T21:47:50.000Z\" albumId=\"2608\" artistId=\"1456\" type=\"podcast\" streamId=\"44626\" description=\"durée : 01:30:06 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Elsa Fottorino (Pianiste), Stéphane Friédérich (Pianiste), Jean-Charles Hoffelé (Diapason, LAvant-Scène Opéra) - réalisé par : Thomas Jost\" status=\"completed\" publishDate=\"2015-05-10T19:00:00.000Z\"/>\n" +
" <episode id=\"609\" parent=\"42169\" isDir=\"false\" title=\"Symphonie n°82 « LOurs » de Haydn\" album=\"Symphonie n°82 « L?Ours » de Haydn\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87052416\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5422\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-03.05.2015-ITEMA_20751006-0.mp3\" isVideo=\"false\" created=\"2015-05-03T21:48:13.000Z\" albumId=\"2607\" artistId=\"1456\" type=\"podcast\" streamId=\"44590\" description=\"durée : 01:30:10 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Philippe Venturini, Emmanuelle Giuliani, Christian Merlin - réalisé par : Cyrielle Weber\" status=\"completed\" publishDate=\"2015-05-03T19:00:00.000Z\"/>\n" +
" <episode id=\"599\" parent=\"42169\" isDir=\"false\" title=\"Leçons de Ténèbres de Couperin\" album=\"Leçons de Ténèbres de Couperin\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"87036032\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5421\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-26.04.2015-ITEMA_20748474-0.mp3\" isVideo=\"false\" created=\"2015-04-26T22:33:12.000Z\" albumId=\"2606\" artistId=\"1456\" type=\"podcast\" streamId=\"42807\" description=\"durée : 01:30:09 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Chantal Cazaux (LAvant-scène Opéra), Piotr Kaminski (Diapason), Philippe Venturini (Les Echos) \n" +
" - réalisé par : Sylvain Richard\" status=\"completed\" publishDate=\"2015-04-26T19:00:00.000Z\"/>\n" +
" <episode id=\"590\" parent=\"42169\" isDir=\"false\" title=\"Impromptus D. 899 de Schubert\" album=\"Impromptus D. 899 de Schubert\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86634624\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5396\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-19.04.2015-ITEMA_20745909-0.mp3\" isVideo=\"false\" created=\"2015-04-20T17:12:16.000Z\" albumId=\"2605\" artistId=\"1456\" type=\"podcast\" streamId=\"42716\" description=\"durée : 01:29:44 - La tribune des critiques de disques - par : Jérémie Rousseau - Bertrand Dermoncourt (Classica), Elsa Fottorino (Pianiste), Emmanuelle Giuliani (La Croix) - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-04-19T19:00:00.000Z\"/>\n" +
" <episode id=\"574\" parent=\"42169\" isDir=\"false\" title=\"Gloria d'Antonio Vivaldi\" album=\"Gloria d'Antonio Vivaldi\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86798464\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5406\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-15.03.2015-ITEMA_20733576-0.mp3\" isVideo=\"false\" created=\"2015-03-16T15:17:04.000Z\" albumId=\"2604\" artistId=\"1456\" type=\"podcast\" streamId=\"42263\" description=\"durée : 01:29:54 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Bigorie (Classica), Chantal Cazaux (LAvant-scène Opéra), Philippe Venturini (Les Echos) \n" +
" - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-03-15T20:00:00.000Z\"/>\n" +
" <episode id=\"565\" parent=\"42169\" isDir=\"false\" title=\"&quot;Lagrime mie&quot; de &quot;L'Eraclito Amoroso&quot; de Barbara Strozzi\" album=\"''Lagrime mie'' de ''L'Eraclito Amoroso'' de Barbara Strozzi\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86646912\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5397\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-08.03.2015-ITEMA_20731103-0.mp3\" isVideo=\"false\" created=\"2015-03-08T23:45:39.000Z\" albumId=\"2603\" artistId=\"1456\" type=\"podcast\" streamId=\"42217\" description=\"durée : 01:29:45 - La tribune des critiques de disques - par : Jérémie Rousseau - thème de la semaine : dans le cadre de la Journée internationale de la femme - Avec Jérémie Bigorie (Classica), Jérémie Cahen (disquaire chez Gibert Joseph) et Jean-Charles Hoffelé (Diapason, L'Avant-Scène opéra) - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-03-08T20:00:00.000Z\"/>\n" +
" <episode id=\"556\" parent=\"42169\" isDir=\"false\" title=\"Concerto pour piano « Jeunehomme » de Wolfgang Amadeus Mozart\" album=\"Concerto pour piano « Jeunehomme » de Wolfgang Amadeus Mozart\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86608000\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5394\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-01.03.2015-ITEMA_20728611-0.mp3\" isVideo=\"false\" created=\"2015-03-02T14:28:25.000Z\" albumId=\"2597\" artistId=\"1456\" type=\"podcast\" streamId=\"41746\" description=\"durée : 01:29:42 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Elsa Fottorino, Stéphane Friédérich, Antoine Mignon - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-03-01T20:00:00.000Z\"/>\n" +
" <episode id=\"546\" parent=\"42169\" isDir=\"false\" title=\"Gnossiennes d'Erik Satie\" album=\"Gnossiennes d'Erik Satie\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86866048\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5410\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-22.02.2015-ITEMA_20726133-0.mp3\" isVideo=\"false\" created=\"2015-02-23T17:47:40.000Z\" albumId=\"2596\" artistId=\"1456\" type=\"podcast\" streamId=\"41705\" description=\"durée : 01:29:58 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Christian Merlin, Bertrand Dermoncourt et Elsa Fottorino - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-02-22T20:00:00.000Z\"/>\n" +
" <episode id=\"513\" parent=\"42169\" isDir=\"false\" title=\"Sextuor n°1 de Johannes Brahms\" album=\"Sextuor n°1 de Johannes Brahms\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86612096\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5394\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-15.02.2015-ITEMA_20723560-0.mp3\" isVideo=\"false\" created=\"2015-02-16T15:30:30.000Z\" albumId=\"2595\" artistId=\"1456\" type=\"podcast\" streamId=\"41592\" description=\"durée : 01:29:42 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jean-Charles Hoffelé, Antoine Mignon, Eric Taver\n" +
" - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-02-15T20:00:00.000Z\"/>\n" +
" <episode id=\"506\" parent=\"42169\" isDir=\"false\" title=\"Cavalleria Rusticana de Pietro Mascagni\" album=\"Cavalleria Rusticana de Pietro Mascagni\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86425728\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5383\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-08.02.2015-ITEMA_20721030-0.mp3\" isVideo=\"false\" created=\"2015-02-09T17:03:05.000Z\" albumId=\"2594\" artistId=\"1456\" type=\"podcast\" streamId=\"40570\" description=\"durée : 01:29:31 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Bigorie (Classica), Chantal Cazaux (L'Avant-Scène Opéra) et Emmanuel Dupuy (Diapason) - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-02-08T20:00:00.000Z\"/>\n" +
" <episode id=\"498\" parent=\"42169\" isDir=\"false\" title=\"Cantate « Weinen, Klagen, Sorgen, Zagen » de Jean-Sébastien Bach\" album=\"Cantate « Weinen, Klagen, Sorgen, Zagen » de Jean-Sébastien Bach\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86556800\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5391\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-01.02.2015-ITEMA_20718534-0.mp3\" isVideo=\"false\" created=\"2015-02-01T21:45:28.000Z\" albumId=\"2598\" artistId=\"1456\" type=\"podcast\" streamId=\"42163\" description=\"durée : 01:29:39 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Bertrand Dermoncourt, Emmanuel Dupuy, Philippe Venturini - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-02-01T20:00:00.000Z\"/>\n" +
" <episode id=\"489\" parent=\"42169\" isDir=\"false\" title=\"Quatuor Américain d'Antonin Dvorak\" album=\"Quatuor Américain d'Antonin Dvorak\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86728832\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5402\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-25.01.2015-ITEMA_20716094-0.mp3\" isVideo=\"false\" created=\"2015-01-25T21:43:55.000Z\" albumId=\"2599\" artistId=\"1456\" type=\"podcast\" streamId=\"42164\" description=\"durée : 01:29:50 - La tribune des critiques de disques - par : Jérémie Rousseau - Emmanuelle Giuliani (La Croix), Antoine Mignon (Classica), Eric Taver (L'Etudiant) élisent la version de référence du Quatuor à cordes n°12 « Américain » dAnton Dvorak.\n" +
" - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-01-25T20:00:00.000Z\"/>\n" +
" <episode id=\"479\" parent=\"42169\" isDir=\"false\" title=\"LArlésienne de Georges Bizet\" album=\"L?Arlésienne de Georges Bizet\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86802560\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5406\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-18.01.2015-ITEMA_20713431-0.mp3\" isVideo=\"false\" created=\"2015-01-19T21:12:44.000Z\" albumId=\"2600\" artistId=\"1456\" type=\"podcast\" streamId=\"42165\" description=\"durée : 01:29:54 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Jérémie Cahen, Stéphane Friédérich, Emmanuelle Giuliani - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-01-18T20:00:00.000Z\"/>\n" +
" <episode id=\"470\" parent=\"42169\" isDir=\"false\" title=\"Sonate Opus 111 de Beethoven\" album=\"Sonate Opus 111 de Beethoven\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86657152\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5397\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-11.01.2015-ITEMA_20710790-0.mp3\" isVideo=\"false\" created=\"2015-01-11T21:15:24.000Z\" albumId=\"2601\" artistId=\"1456\" type=\"podcast\" streamId=\"42166\" description=\"durée : 01:29:45 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Elsa Fottorino, Christian Merlin, Antoine Mignon - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-01-11T20:00:00.000Z\"/>\n" +
" <episode id=\"461\" parent=\"42169\" isDir=\"false\" title=\"Le Beau Danube Bleu de Johann Strauss\" album=\"Le Beau Danube Bleu de Johann Strauss\" artist=\"Jérémie Rousseau\" genre=\"Podcast\" coverArt=\"42169\" size=\"86569088\" contentType=\"audio/mpeg\" suffix=\"mp3\" duration=\"5392\" bitRate=\"128\" path=\"La tribune des critiques de disques/13183-04.01.2015-ITEMA_20708450-0.mp3\" isVideo=\"false\" created=\"2015-01-04T20:49:53.000Z\" albumId=\"2602\" artistId=\"1456\" type=\"podcast\" streamId=\"42167\" description=\"durée : 01:29:40 - La tribune des critiques de disques - par : Jérémie Rousseau - Avec Emmanuelle Giuliani (La Croix), Christian Merlin (Le Figaro) et Bertrand Dermoncourt (Classica, L'Express). - réalisé par : Géraldine Prutner\" status=\"completed\" publishDate=\"2015-01-04T20:00:00.000Z\"/>\n" +
" </channel>\n" +
" </podcasts>\n" +
"</subsonic-response>\n";
public static Reader getReader() {
return new StringReader(data);
}
}

View File

@ -0,0 +1,41 @@
package org.moire.ultrasonic.Test.service;
import java.io.Reader;
import java.io.StringReader;
/**
* Created by rcocula on 11/03/2016.
*/
public class GetPodcastTestReaderProvider {
private static String data = "<subsonic-response status=\"ok\" version=\"1.12.0\" xmlns=\"http://subsonic.org/restapi\">\n" +
" <podcasts>\n" +
" <channel id=\"0\" url=\"http://radiofrance-podcast.net/podcast09/rss_13183.xml\" title=\"La tribune des critiques de disques\" description=\"Sous la houlette de Jérémie Rousseau, d'éminents critiques musicaux écoutent à l'aveugle différentes versions d'une oeuvre du répertoire et la commentent\" status=\"completed\"/>\n" +
" <channel id=\"1\" url=\"http://radiofrance-podcast.net/podcast09/rss_11874.xml\" title=\"La Matinale du samedi\" description=\"Une version détendue pour les matinaux du week end\" status=\"completed\"/>\n" +
" <channel id=\"2\" url=\"http://radiofrance-podcast.net/podcast09/rss_10467.xml\" title=\"LES NOUVEAUX CHEMINS DE LA CONNAISSANCE\" description=\"Une rencontre quotidienne entre philosophie et monde contemporain.\" status=\"completed\"/>\n" +
" <channel id=\"3\" url=\"http://radiofrance-podcast.net/podcast09/rss_12087.xml\" title=\"Alla Breve, l'intégrale\" description=\"Une oeuvre courte, commandée à un compositeur d aujourd hui, diffusée en 5 mouvements durant la semaine et proposée en podcast dans son intégralité.\" status=\"completed\"/>\n" +
" <channel id=\"4\" url=\"http://lescastcodeurs.libsyn.com/rss\" title=\"Les Cast Codeurs Podcast\" description=\"Le podcast Java en Français dans le texte\" status=\"completed\"/>\n" +
" <channel id=\"6\" url=\"http://radiofrance-podcast.net/podcast09/rss_14003.xml\" title=\"Le cri du patchwork\" description=\"Si le patchwork était un animal, quel serait son cri ?\" status=\"completed\"/>\n" +
" <channel id=\"7\" url=\"http://radiofrance-podcast.net/podcast09/rss_12289.xml\" title=\"Electromania\" description=\"Electromania continue de témoigner de toutes les musiques avant tout inventives et inclassables, de Pierre Henry à Nick Cave.\" status=\"completed\"/>\n" +
" <channel id=\"8\" url=\"http://radiofrance-podcast.net/podcast09/rss_11910.xml\" title=\"CONTINENT MUSIQUE\" description=\"Funk, baroque, jazz, électro, classique, chanson, musique concrète ou hip-hop abstrait...\" status=\"completed\"/>\n" +
" <channel id=\"9\" url=\"http://radiofrance-podcast.net/podcast09/rss_11985.xml\" title=\"SUPERSONIC\" description=\"Un homme ou une femme de son fait partager ses créations et son univers\" status=\"completed\"/>\n" +
" <channel id=\"10\" url=\"http://radiofrance-podcast.net/podcast09/rss_12668.xml\" title=\"Label pop\" description=\"Chaque semaine, une oreille attentive à l'actualité, pour restituer l'éclatante vitalité de la pop moderne, entendue au sens le plus large\" status=\"completed\"/>\n" +
" <channel id=\"11\" url=\"http://radiofrance-podcast.net/podcast09/rss_11224.xml\" title=\"Le magazine de la contemporaine\" description=\"Interviews et reportages autour de l'actualité de la musique contemporaine\" status=\"completed\"/>\n" +
" <channel id=\"12\" url=\"http://radiofrance-podcast.net/podcast09/rss_11393.xml\" title=\"Les greniers de la mémoire\" description=\"Une visite complice et nostalgique des archives musicales de Radio France\" status=\"completed\"/>\n" +
" <channel id=\"13\" url=\"http://radiofrance-podcast.net/podcast09/rss_14498.xml\" title=\"Musicopolis\" description=\"Une ville, un compositeur, une époque. Une histoire de la musique racontée chaque semaine.\" status=\"completed\"/>\n" +
" <channel id=\"14\" url=\"http://radiofrance-podcast.net/podcast09/rss_14603.xml\" title=\"On ne peut pas tout savoir\" description=\"Parce qu'on ne peut pas tout savoir, Arnaud Merlin vous propose chaque semaine un voyage dans un univers musical différent.\" status=\"completed\"/>\n" +
" <channel id=\"15\" url=\"http://radiofrance-podcast.net/podcast09/rss_12576.xml\" title=\"LES CARNETS DE L'ECONOMIE\" description=\"Un chercheur ou un acteur de la sphère économique et sociale nous livre un concentré de ses travaux et de sa réflexion\" status=\"completed\"/>\n" +
" <channel id=\"16\" url=\"http://radiofrance-podcast.net/podcast09/rss_14076.xml\" title=\"LES CARNETS DE LA CREATION\" description=\"LES CARNETS DE LA CREATION\" status=\"completed\"/>\n" +
" <channel id=\"18\" url=\"http://radiofrance-podcast.net/podcast09/rss_14663.xml\" title=\"LE MONDE SELON XAVIER DELAPORTE\" description=\"LE MONDE SELON XAVIER DELAPORTE\" status=\"completed\"/>\n" +
" <channel id=\"19\" url=\"http://radiofrance-podcast.net/podcast09/rss_16260.xml\" title=\"LA SUITE DANS LES IDEES\" description=\"Contribuer à alimenter le débat public par les idées\" status=\"completed\"/>\n" +
" <channel id=\"20\" url=\"http://radiofrance-podcast.net/podcast09/rss_13959.xml\" title=\"CULTURE MUSIQUE\" description=\"CULTURE MUSIQUE\" status=\"completed\"/>\n" +
" <channel id=\"21\" url=\"http://radiofrance-podcast.net/podcast09/rss_14009.xml\" title=\"Carnets de voyages\" description=\"Carnet de voyage est un atlas ouvert sur les musiques que l'on dit de tradition orale ou extra-européennes.\" status=\"completed\"/>\n" +
" </podcasts>\n" +
"</subsonic-response>\n";
public static Reader getReader() {
return new StringReader(data);
}
}

View File

@ -0,0 +1,133 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.activity;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.Playlist;
import org.moire.ultrasonic.domain.PodcastsChannel;
import org.moire.ultrasonic.service.MusicService;
import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.service.OfflineException;
import org.moire.ultrasonic.service.ServerTooOldException;
import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CacheCleaner;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.LoadingTask;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.PlaylistAdapter;
import org.moire.ultrasonic.view.PodcastsChannelsAdapter;
import java.util.List;
public class PodcastsActivity extends SubsonicTabActivity {
private View emptyTextView;
SubsonicTabActivity currentActivity = null;
ListView channelItemsListView = null;
Context currentContext = (Context)this;
@Override
public void onCreate(Bundle savedInstanceState)
{
this.currentActivity = this;
super.onCreate(savedInstanceState);
setContentView(R.layout.podcasts);
emptyTextView = findViewById(R.id.select_podcasts_empty);
channelItemsListView = (ListView)findViewById(R.id.podcasts_channels_items_list);
channelItemsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
PodcastsChannel pc = (PodcastsChannel) parent.getItemAtPosition(position);
if (pc == null) {
return;
}
Intent intent = new Intent(currentContext, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_PODCAST_CHANNEL_ID, pc.getId());
startActivityForResultWithoutTransition(PodcastsActivity.this, intent);
}
});
load();
}
private void load()
{
BackgroundTask<List<PodcastsChannel>> task = new TabActivityBackgroundTask<List<PodcastsChannel>>(this, true)
{
@Override
protected List<PodcastsChannel> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(PodcastsActivity.this);
List<PodcastsChannel> channels = musicService.getPodcastsChannels(false,PodcastsActivity.this, this);
/* TODO c'est quoi ce nettoyage de cache ?
if (!Util.isOffline(PodcastsActivity.this))
new CacheCleaner(PodcastsActivity.this, getDownloadService()).cleanPlaylists(playlists);
*/
return channels;
}
@Override
protected void done(List<PodcastsChannel> result)
{
channelItemsListView.setAdapter(new PodcastsChannelsAdapter(currentActivity, result));
emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE);
}
};
task.execute();
}
}

View File

@ -278,6 +278,7 @@ public class SelectAlbumActivity extends SubsonicTabActivity
String name = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME);
String parentId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID);
String playlistId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
String podcastChannelId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PODCAST_CHANNEL_ID);
String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
String shareId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_SHARE_ID);
String shareName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_SHARE_NAME);
@ -297,6 +298,9 @@ public class SelectAlbumActivity extends SubsonicTabActivity
{
getPlaylist(playlistId, playlistName);
}
else if (podcastChannelId != null) {
getPodcastEpisodes(podcastChannelId);
}
else if (shareId != null)
{
getShare(shareId, shareName);
@ -852,6 +856,21 @@ public class SelectAlbumActivity extends SubsonicTabActivity
}.execute();
}
private void getPodcastEpisodes(final String podcastChannelId)
{
// TODO on fait quoi ?
//setActionBarSubtitle(playlistName);
new LoadTask()
{
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return service.getPodcastEpisodes(podcastChannelId, SelectAlbumActivity.this, this);
}
}.execute();
}
private void getShare(final String shareId, final CharSequence shareName)
{
setActionBarSubtitle(shareName);

View File

@ -151,6 +151,7 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
findViewById(R.id.menu_browse).setOnClickListener(this);
findViewById(R.id.menu_search).setOnClickListener(this);
findViewById(R.id.menu_playlists).setOnClickListener(this);
findViewById(R.id.menu_podcasts).setOnClickListener(this);
sharesMenuItem.setOnClickListener(this);
chatMenuItem.setOnClickListener(this);
bookmarksMenuItem.setOnClickListener(this);
@ -1436,6 +1437,11 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivityForResultWithoutTransition(SubsonicTabActivity.this, intent);
break;
case R.id.menu_podcasts:
intent = new Intent(SubsonicTabActivity.this, PodcastsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivityForResultWithoutTransition(SubsonicTabActivity.this, intent);
break;
case R.id.menu_shares:
intent = new Intent(SubsonicTabActivity.this, ShareActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

View File

@ -0,0 +1,94 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.domain;
import java.io.Serializable;
/**
* @author Sindre Mehus
*/
public class PodcastEpisode implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -4160515427075433798L;
private String id;
private String title;
private String url;
private String description;
private String status;
public PodcastEpisode(String id, String title, String url, String description, String status)
{
this.id = id;
this.title = title;
this.url = url;
this.description = description;
this.status = status;
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return getTitle();
}
}

View File

@ -0,0 +1,94 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.domain;
import java.io.Serializable;
/**
* @author Sindre Mehus
*/
public class PodcastsChannel implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -4160515427075433798L;
private String id;
private String title;
private String url;
private String description;
private String status;
public PodcastsChannel(String id, String title,String url, String description, String status)
{
this.id = id;
this.title = title;
this.url = url;
this.description = description;
this.status = status;
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return getTitle();
}
}

View File

@ -30,6 +30,7 @@ import org.moire.ultrasonic.domain.Lyrics;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.domain.MusicFolder;
import org.moire.ultrasonic.domain.Playlist;
import org.moire.ultrasonic.domain.PodcastsChannel;
import org.moire.ultrasonic.domain.SearchCriteria;
import org.moire.ultrasonic.domain.SearchResult;
import org.moire.ultrasonic.domain.Share;
@ -66,6 +67,7 @@ public class CachedMusicService implements MusicService
private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
private final TimeLimitedCache<Indexes> cachedArtists = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<List<Playlist>>(3600, TimeUnit.SECONDS);
private final TimeLimitedCache<List<PodcastsChannel>> cachedPodcastsChannels = new TimeLimitedCache<List<PodcastsChannel>>(3600, TimeUnit.SECONDS);
private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS);
private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<List<Genre>>(10 * 3600, TimeUnit.SECONDS);
@ -215,6 +217,24 @@ public class CachedMusicService implements MusicService
return musicService.getPlaylist(id, name, context, progressListener);
}
@Override
public List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
List<PodcastsChannel> result = refresh ? null : cachedPodcastsChannels.get();
if (result == null)
{
result = musicService.getPodcastsChannels(refresh, context, progressListener);
cachedPodcastsChannels.set(result);
}
return result;
}
@Override
public MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context, ProgressListener progressListener) throws Exception {
return musicService.getPodcastEpisodes(podcastChannelId,context,progressListener);
}
@Override
public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
@ -532,4 +552,5 @@ public class CachedMusicService implements MusicService
{
return musicService.getAvatar(context, username, size, saveToFile, highQuality, progressListener);
}
}

View File

@ -21,6 +21,7 @@ package org.moire.ultrasonic.service;
import android.content.Context;
import android.graphics.Bitmap;
import org.moire.ultrasonic.activity.SelectAlbumActivity;
import org.moire.ultrasonic.domain.Bookmark;
import org.moire.ultrasonic.domain.ChatMessage;
import org.moire.ultrasonic.domain.Genre;
@ -30,6 +31,8 @@ import org.moire.ultrasonic.domain.Lyrics;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.domain.MusicFolder;
import org.moire.ultrasonic.domain.Playlist;
import org.moire.ultrasonic.domain.PodcastEpisode;
import org.moire.ultrasonic.domain.PodcastsChannel;
import org.moire.ultrasonic.domain.SearchCriteria;
import org.moire.ultrasonic.domain.SearchResult;
import org.moire.ultrasonic.domain.Share;
@ -74,6 +77,8 @@ public interface MusicService
MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception;
List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception;
@ -149,4 +154,6 @@ public interface MusicService
void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception;
Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception;
MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context, ProgressListener progressListener) throws Exception;
}

View File

@ -26,6 +26,7 @@ import android.net.NetworkInfo;
import android.util.Log;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.Test.service.GetPodcastEpisodesTestReaderProvider;
import org.moire.ultrasonic.domain.Bookmark;
import org.moire.ultrasonic.domain.ChatMessage;
import org.moire.ultrasonic.domain.Genre;
@ -35,6 +36,8 @@ import org.moire.ultrasonic.domain.Lyrics;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.domain.MusicFolder;
import org.moire.ultrasonic.domain.Playlist;
import org.moire.ultrasonic.domain.PodcastEpisode;
import org.moire.ultrasonic.domain.PodcastsChannel;
import org.moire.ultrasonic.domain.SearchCriteria;
import org.moire.ultrasonic.domain.SearchResult;
import org.moire.ultrasonic.domain.ServerInfo;
@ -54,6 +57,8 @@ import org.moire.ultrasonic.service.parser.MusicDirectoryParser;
import org.moire.ultrasonic.service.parser.MusicFoldersParser;
import org.moire.ultrasonic.service.parser.PlaylistParser;
import org.moire.ultrasonic.service.parser.PlaylistsParser;
import org.moire.ultrasonic.service.parser.PodcastEpisodeParser;
import org.moire.ultrasonic.service.parser.PodcastsChannelsParser;
import org.moire.ultrasonic.service.parser.RandomSongsParser;
import org.moire.ultrasonic.service.parser.SearchResult2Parser;
import org.moire.ultrasonic.service.parser.SearchResultParser;
@ -66,6 +71,7 @@ import org.moire.ultrasonic.util.CancellableTask;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.FileUtil;
import org.moire.ultrasonic.util.ProgressListener;
import org.moire.ultrasonic.util.StreamProxy;
import org.moire.ultrasonic.util.Util;
import org.apache.http.Header;
@ -104,6 +110,8 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
@ -111,6 +119,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import static java.util.Arrays.asList;
@ -594,6 +603,43 @@ public class RESTMusicService implements MusicService
}
}
@Override
public List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
Reader reader = getReader(context, progressListener, "getPodcasts", null,"includeEpisodes", "false");
try {
return new PodcastsChannelsParser(context).parse(reader, progressListener);
}
finally
{
Util.close(reader);
}
}
@Override
public MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context, ProgressListener progressListener) throws Exception {
List<String> names = new ArrayList<String>();
names.add("id");
names.add("includeEpisodes");
List<Object> values = new ArrayList<Object>();
values.add(podcastChannelId);
values.add("true");
// TODO
Reader reader = getReader(context, progressListener, "getPodcasts", null, names,values);
//Reader reader = GetPodcastEpisodesTestReaderProvider.getReader();
try {
return new PodcastEpisodeParser(context).parse(reader, progressListener);
}
finally
{
Util.close(reader);
}
}
@Override
public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
@ -1741,4 +1787,5 @@ public class RESTMusicService implements MusicService
return Util.scaleBitmap(bitmap, size);
}
}
}

View File

@ -0,0 +1,143 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.service.parser;
import android.content.Context;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.domain.PodcastEpisode;
import org.moire.ultrasonic.domain.PodcastsChannel;
import org.moire.ultrasonic.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* @author Sindre Mehus
*/
public class PodcastEpisodeParser extends AbstractParser
{
public PodcastEpisodeParser(Context context)
{
super(context);
}
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception
{
MusicDirectory musicDirectory = new MusicDirectory();
SortedMap<Date,MusicDirectory.Entry> sortedEntries = new TreeMap<Date, MusicDirectory.Entry>();
Locale currentLocale = getContext().getResources().getConfiguration().locale;
DateFormat shortDateFormat = DateFormat.getDateTimeInstance(
DateFormat.SHORT,
DateFormat.SHORT, currentLocale);
DateFormat parseDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
updateProgress(progressListener, R.string.parser_reading);
init(reader);
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String tag = getElementName();
if ("episode".equals(tag))
{
String status = get("status");
if (!"skipped".equals(status) && !"error".equals(status)) {
MusicDirectory.Entry entry = new MusicDirectory.Entry();
String streamId = get("streamId");
entry.setId(streamId);
entry.setIsDirectory(Boolean.parseBoolean(get("isDir")));
entry.setIsVideo(Boolean.parseBoolean(get("isVideo")));
entry.setType(get("type"));
entry.setPath(get("path"));
entry.setSuffix(get("suffix"));
String size = get("size");
if (size != null) {
entry.setSize(Long.parseLong(size));
}
entry.setCoverArt(get("coverArt"));
entry.setAlbum(get("album"));
entry.setTitle(get("title"));
entry.setAlbumId(get("albumId"));
entry.setArtist(get("artist"));
entry.setArtistId(get("artistId"));
String bitRate = get("bitRate");
if (bitRate != null) {
entry.setBitRate(Integer.parseInt(get("bitRate")));
}
entry.setContentType(get("contentType"));
String duration = get("duration");
if (duration != null) {
entry.setDuration(Long.parseLong(duration));
}
entry.setGenre(get("genre"));
entry.setParent(get("parent"));
entry.setCreated("created");
String publishDate = get("publishDate");
if (publishDate != null) {
try {
Date publishDateDate = parseDateFormat.parse(publishDate);
entry.setArtist(shortDateFormat.format(publishDateDate));
sortedEntries.put(publishDateDate, entry);
} catch (Exception e) {
// nothing to do
}
}
}
}
else if ("error".equals(tag))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
for (Date pubDate : sortedEntries.keySet()) {
musicDirectory.addFirst(sortedEntries.get(pubDate));
}
return musicDirectory;
}
}

View File

@ -0,0 +1,81 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.service.parser;
import android.content.Context;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.Playlist;
import org.moire.ultrasonic.domain.PodcastsChannel;
import org.moire.ultrasonic.util.ProgressListener;
import org.moire.ultrasonic.view.PlaylistAdapter;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* @author Sindre Mehus
*/
public class PodcastsChannelsParser extends AbstractParser
{
public PodcastsChannelsParser(Context context)
{
super(context);
}
public List<PodcastsChannel> parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<PodcastsChannel> result = new ArrayList<PodcastsChannel>();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String tag = getElementName();
if ("channel".equals(tag))
{
String id = get("id");
String title = get("title");
String url = get("url");
String description = get("description");
String status = get("status");
result.add(new PodcastsChannel(id,title, url,description,status));
}
else if ("error".equals(tag))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return result;
}
}

View File

@ -41,6 +41,7 @@ public final class Constants
public static final String INTENT_EXTRA_NAME_AUTOPLAY = "subsonic.playall";
public static final String INTENT_EXTRA_NAME_QUERY = "subsonic.query";
public static final String INTENT_EXTRA_NAME_PLAYLIST_ID = "subsonic.playlist.id";
public static final String INTENT_EXTRA_NAME_PODCAST_CHANNEL_ID = "subsonic.podcastChannel.id";
public static final String INTENT_EXTRA_NAME_PARENT_ID = "subsonic.parent.id";
public static final String INTENT_EXTRA_NAME_PLAYLIST_NAME = "subsonic.playlist.name";
public static final String INTENT_EXTRA_NAME_SHARE_ID = "subsonic.share.id";

View File

@ -0,0 +1,83 @@
package org.moire.ultrasonic.view;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.activity.SubsonicTabActivity;
import org.moire.ultrasonic.domain.Playlist;
import org.moire.ultrasonic.domain.PodcastsChannel;
import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author Sindre Mehus
*/
public class PodcastsChannelsAdapter extends ArrayAdapter<PodcastsChannel>
{
//private final SubsonicTabActivity activity;
public PodcastsChannelsAdapter(Activity activity, List<PodcastsChannel> channels)
{
super(activity, R.layout.podcasts_channel_item, channels);
//this.activity = activity;
}
@Override
public void add(PodcastsChannel object) {
super.add(object);
}
/* @Override
public View getView(int position, View convertView, ViewGroup parent)
{
PodcastsChannel entry = getItem(position);
PlaylistView view;
if (convertView != null && convertView instanceof PlaylistView)
{
PlaylistView currentView = (PlaylistView) convertView;
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
view = currentView;
view.setViewHolder(viewHolder);
}
else
{
view = new PlaylistView(activity);
view.setLayout();
}
view.setPlaylist(entry);
return view;
}
*/
/* public static class PlaylistComparator implements Comparator<Playlist>, Serializable
{
private static final long serialVersionUID = -6201663557439120008L;
@Override
public int compare(Playlist playlist1, Playlist playlist2)
{
return playlist1.getName().compareToIgnoreCase(playlist2.getName());
}
public static List<Playlist> sort(List<Playlist> playlists)
{
Collections.sort(playlists, new PlaylistComparator());
return playlists;
}
} */
/* static class ViewHolder
{
TextView name;
} */
}

View File

@ -0,0 +1,63 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.view;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.TextView;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.Playlist;
/**
* Used to display playlists in a {@code ListView}.
*
* @author Sindre Mehus
*/
public class PodcatsChannelItemView extends UpdateView
{
private Context context;
private PlaylistAdapter.ViewHolder viewHolder;
public PodcatsChannelItemView(Context context)
{
super(context);
this.context = context;
}
public void setLayout()
{
LayoutInflater.from(context).inflate(R.layout.playlist_list_item, this, true);
viewHolder = new PlaylistAdapter.ViewHolder();
viewHolder.name = (TextView) findViewById(R.id.playlist_name);
setTag(viewHolder);
}
public void setViewHolder(PlaylistAdapter.ViewHolder viewHolder)
{
this.viewHolder = viewHolder;
setTag(this.viewHolder);
}
public void setPlaylist(Playlist playlist)
{
viewHolder.name.setText(playlist.getName());
update();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -81,6 +81,14 @@
android:drawableLeft="?attr/media_play"
android:text="@string/button_bar.now_playing"/>
<TextView
android:id="@+id/menu_podcasts"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="?attr/podcasts"
android:text="@string/button_bar.podcasts"/>
<TextView
android:id="@+id/menu_common"
style="@style/MenuDrawer.Widget.Category"

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:layout_width="fill_parent"
a:layout_height="fill_parent"
a:orientation="vertical" >
<include layout="@layout/tab_progress" />
<TextView
a:id="@+id/select_podcasts_empty"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:padding="10dip"
a:text="@string/podcasts_channels.empty"
a:visibility="gone" />
<ListView
a:id="@+id/podcasts_channels_items_list"
a:layout_width="fill_parent"
a:layout_height="0dip"
a:layout_weight="1.0"
a:fastScrollEnabled="true"
a:textFilterEnabled="true" />
<include layout="@layout/now_playing" />
</LinearLayout>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/podcast_channel_item"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:padding="10dip"
a:visibility="visible" />

View File

@ -12,6 +12,9 @@
<string name="button_bar.chat">Chat</string>
<string name="button_bar.home">UltraSonic Main</string>
<string name="button_bar.now_playing">Now Playing</string>
<string name="podcasts.label">Podcast</string>
<string name="podcasts_channels.empty">No podcasts channels registered</string>
<string name="button_bar.podcasts">Podcast</string>
<string name="button_bar.playlists">Playlists</string>
<string name="button_bar.search">Search</string>
<string name="chat.send_a_message">Send a message</string>

View File

@ -80,6 +80,7 @@
<attr name="media_repeat_single" format="reference"/>
<attr name="media_shuffle" format="reference"/>
<attr name="media_play" format="reference"/>
<attr name="podcasts" format="reference"/>
<attr name="media_play_next" format="reference"/>
<attr name="media_play_small" format="reference"/>
<attr name="media_stop" format="reference"/>

View File

@ -35,6 +35,7 @@
<item name="media_repeat_single">@drawable/media_repeat_single</item>
<item name="media_shuffle">@drawable/media_shuffle_normal_dark</item>
<item name="media_play">@drawable/media_start_normal_dark</item>
<item name="podcasts">@drawable/ic_menu_podcasts_dark</item>
<item name="media_play_next">@drawable/media_play_next</item>
<item name="media_play_small">@drawable/ic_stat_play_dark</item>
<item name="media_stop">@drawable/media_stop_normal_dark</item>
@ -79,6 +80,7 @@
<item name="media_repeat_single">@drawable/media_repeat_single</item>
<item name="media_shuffle">@drawable/media_shuffle_normal_light</item>
<item name="media_play">@drawable/media_start_normal_light</item>
<item name="podcasts">@drawable/ic_menu_podcasts_light</item>
<item name="media_play_next">@drawable/media_play_next</item>
<item name="media_play_small">@drawable/ic_stat_play_light</item>
<item name="media_stop">@drawable/media_stop_normal_light</item>