1
0
mirror of https://github.com/ultrasonic/ultrasonic synced 2025-03-06 04:17:38 +01:00

podcasts feature

Work on podcats

Work on podcats

podcasts

Dont't bypass the context menu in long click on album view.

Work on podcats

Work on podcats

Work on podcats

podcasts

If items are maximized they will return to minimize form when scrolling.
(cherry picked from commit ada247d)

podcasts

Podcasts icon

podcasts

podcasts
(cherry picked from commit b4ff614)
This commit is contained in:
rcocula 2016-02-26 10:40:52 +01:00 committed by biconou
parent 3f2f59020c
commit e3e90cebf1
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)) {
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>