Advertisement
NLinker

Rx Spotify Example Scala version

Oct 14th, 2016
1,202
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 11.66 KB | None | 0 0
  1. package com.vertigo.crawler
  2.  
  3. import java.util.Random
  4.  
  5. import com.vertigo.model.enums.{EntityType, Provider}
  6. import com.vertigo.model.json.sync.CrawlerTask
  7. import com.vertigo.test.util.RandomUtil
  8. import com.wrapper.spotify.models._
  9. import rx.lang.scala.Observable
  10.  
  11. import scala.collection.JavaConverters._
  12. import scala.collection.{mutable ⇒ m}
  13. import scala.util
  14.  
  15.  
  16. /*
  17.     Add to pom
  18.  
  19.  
  20.       <plugin>
  21.         <groupId>org.scala-tools</groupId>
  22.         <artifactId>maven-scala-plugin</artifactId>
  23.         <executions>
  24.           <execution>
  25.             <goals>
  26.               <goal>compile</goal>
  27.               <goal>testCompile</goal>
  28.             </goals>
  29.           </execution>
  30.         </executions>
  31.         <configuration>
  32.           <jvmArgs>
  33.             <jvmArg>-Xms64m</jvmArg>
  34.             <jvmArg>-Xmx1024m</jvmArg>
  35.           </jvmArgs>
  36.         </configuration>
  37.       </plugin>
  38.  
  39.     <dependency>
  40.       <groupId>io.reactivex</groupId>
  41.       <artifactId>rxjava</artifactId>
  42.     </dependency>
  43.     <dependency>
  44.       <groupId>org.scala-lang</groupId>
  45.       <artifactId>scala-library</artifactId>
  46.       <version>2.11.8</version>
  47.     </dependency>
  48.     <dependency>
  49.       <groupId>io.reactivex</groupId>
  50.       <artifactId>rxscala_2.11</artifactId>
  51.       <version>0.26.3</version>
  52.     </dependency>
  53.  */
  54. object Example extends App {
  55.   val random = new Random(69)
  56.   val ru = new RandomUtil(random)
  57.   val genres = m.Buffer(
  58.     "aggrotech", "ebm", "electro-industrial", "futurepop",
  59.     "ambient psychill", "psychill", "ambient", "metal",
  60.     "crossover thrash", "death metal", "groove metal",
  61.     "nwobhm", "speed metal", "thrash metal", "digital hardcore",
  62.     "industrial", "industrial metal", "industrial rock",
  63.     "neue deutsche harte", "album rock", "alternative metal",
  64.     "classic rock", "hard rock", "nu metal", "power metal",
  65.     "rock", "wrestling")
  66.   val markets = m.Buffer(
  67.     "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH",
  68.     "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE",
  69.     "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "ID",
  70.     "IE", "IS", "IT", "JP", "LI", "LT", "LU", "LV", "MC", "MT",
  71.     "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL",
  72.     "PT", "PY", "SE", "SG", "SK", "SV", "TR", "TW", "US", "UY"
  73.   )
  74.   val va: Artist = {
  75.     val ar = new Artist()
  76.     ar.setId("0LyfQWJT6nXafLPZqxe9Of")
  77.     ar.setName("Various Artists")
  78.     ar.setFollowers({
  79.       val f = new Followers()
  80.       f.setHref(null)
  81.       f.setTotal(215138)
  82.       f
  83.     })
  84.     ar.setExternalUrls({
  85.       val e = new ExternalUrls()
  86.       e.getExternalUrls.put("spotify",
  87.         "https://open.spotify.com/artist/" + ar.getId)
  88.       e
  89.     })
  90.     ar.setGenres(Seq.empty.asJava)
  91.     ar.setHref("https://api.spotify.com/v1/artists/" + ar.getId)
  92.     ar.setImages(Seq.empty.asJava)
  93.     ar.setPopularity(0)
  94.     ar.setUri("spotify:artist:" + ar.getId)
  95.     ar
  96.   }
  97.  
  98.   def simplify(a: Album): SimpleAlbum = {
  99.     val sa = new SimpleAlbum()
  100.     sa.setAlbumType(a.getAlbumType)
  101.     sa.setExternalUrls(a.getExternalUrls)
  102.     sa.setHref(a.getHref)
  103.     sa.setId(a.getId)
  104.     sa.setImages(a.getImages)
  105.     sa.setName(a.getName)
  106.     sa.setType(a.getType)
  107.     sa.setUri(a.getUri)
  108.     sa.setAvailableMarkets(a.getAvailableMarkets)
  109.     sa
  110.   }
  111.  
  112.   def simplify(t: Track): SimpleTrack = {
  113.     val sa = new SimpleTrack()
  114.     sa.setDiscNumber(t.getDiscNumber)
  115.     sa.setDuration(t.getDuration)
  116.     sa.setExplicit(t.isExplicit)
  117.     sa.setExternalUrls(t.getExternalUrls)
  118.     sa.setHref(t.getHref)
  119.     sa.setId(t.getId)
  120.     sa.setName(t.getName)
  121.     sa.setPreviewUrl(t.getPreviewUrl)
  122.     sa.setTrackNumber(t.getTrackNumber)
  123.     sa.setType(t.getType)
  124.     sa.setUri(t.getUri)
  125.     sa.setAvailableMarkets(t.getAvailableMarkets)
  126.     sa
  127.   }
  128.  
  129.   def simplify(a: Artist): SimpleArtist = {
  130.     val sa = new SimpleArtist()
  131.     sa.setExternalUrls(a.getExternalUrls)
  132.     sa.setHref(a.getHref)
  133.     sa.setId(a.getId)
  134.     sa.setName(a.getName)
  135.     sa.setType(a.getType)
  136.     sa.setUri(a.getUri)
  137.     sa
  138.   }
  139.  
  140.   /**
  141.     * Select random elements from base list.
  142.     * Must be count <= base.size()
  143.     */
  144.   def listFrom[T](ru: RandomUtil,
  145.                   base: Seq[T],
  146.                   count: Int): Seq[T] = {
  147.     val n = base.size
  148.     val ts = base.toBuffer
  149.     // remove random elements from there
  150.     for (i ← 0 to (n - count)) {
  151.       ts.remove(ru.nextInt(n - i))
  152.     }
  153.     ts
  154.   }
  155.  
  156.   def generateArtist(ru: RandomUtil): Artist = {
  157.     val a = new Artist()
  158.     a.setId(ru.string(8))
  159.     a.setName("artist_" + a.getId)
  160.     a.setPopularity(ru.nextInt(100))
  161.     a.setExternalUrls({
  162.         val eu = new ExternalUrls()
  163.         eu.getExternalUrls.put("spotify",
  164.           "https://open.spotify.com/artist/" + a.getId)
  165.         eu
  166.       })
  167.     a.setHref("https://api.spotify.com/v1/artists/" + a.getId)
  168.     a.setUri("spotify:artist:" + a.getId)
  169.     a.setGenres(listFrom(ru, genres, 3).asJava)
  170.     a.setFollowers({
  171.       val f = new Followers()
  172.       f.setTotal(ru.nextInt(1000))
  173.       f
  174.     })
  175.     a
  176.   }
  177.  
  178.   def generateAlbum(ru: RandomUtil,
  179.                     albumType: AlbumType,
  180.                     creators: Seq[Artist]): Album = {
  181.     val al = new Album()
  182.     al.setId(ru.string(9))
  183.     al.setName("album_" + al.getId)
  184.     al.setAlbumType(albumType)
  185.     al.setHref("https://api.spotify.com/v1/albums/" + al.getId)
  186.     al.setUri("spotify:album:" + al.getId)
  187.     al.setCopyrights({
  188.       val c1 = new Copyright()
  189.       c1.setText("2016 Alpha Matrix")
  190.       c1.setText("C")
  191.       val c2 = new Copyright()
  192.       c2.setText("2016 Alpha Matrix")
  193.       c2.setText("P")
  194.       Seq(c1, c2).asJava
  195.     })
  196.     al.setArtists(creators.map(simplify).asJava)
  197.     al
  198.   }
  199.  
  200.   def generateTrack(ru: RandomUtil,
  201.                     album: Album,
  202.                     trackNumber: Int): Track = {
  203.     val t = new Track()
  204.     t.setId(ru.string(10))
  205.     t.setName("track_" + t.getId)
  206.     t.setHref("https://api.spotify.com/v1/tracks/" + t.getId)
  207.     t.setUri("spotify:track:" + t.getId)
  208.     t.setArtists(album.getArtists)
  209.     t.setAlbum(simplify(album))
  210.     t.setTrackNumber(trackNumber)
  211.     // from 1 to 1000 second
  212.     t.setDuration((ru.nextInt(1000) + 1) * 1000)
  213.     t.setPopularity(ru.nextInt(10))
  214.     t.setAvailableMarkets(album.getAvailableMarkets)
  215.     t.setDiscNumber(0)
  216.     t.setPreviewUrl("https://spotify.com/preview/" + t.getId)
  217.     t
  218.   }
  219.  
  220.   def randomTask(ru: RandomUtil): CrawlerTask = {
  221.     // set only entityType and externalId,
  222.     // the rest of them should be populated by
  223.     val ct = new CrawlerTask()
  224.     ct.setEntityType(EntityType.fromInt(ru.nextInt(11, 13)))
  225.     ct.setExternalId(ru.string(10))
  226.     ct.setProvider(Provider.Spotify)
  227.     ct
  228.   }
  229.  
  230.   def randomTasks(ru: RandomUtil,
  231.                   sws: SpotifyWSImpl,
  232.                   count: Int): Seq[CrawlerTask] = {
  233.     val keys1 = sws.artistMap.keys.toBuffer
  234.     val keys2 = sws.albumMap.keys.toBuffer
  235.     val keys3 = sws.trackMap.keys.toBuffer
  236.     val n1 = keys1.size
  237.     val n2 = keys2.size
  238.     val n3 = keys3.size
  239.     (1 to count).map { _
  240.       val n: Int = ru.nextInt(n1 + n2 + n3)
  241.       val (i, et) =
  242.         if (n < n1) (n, EntityType.Artist)
  243.         else if (n1 <= n && n < n2) (n - n1, EntityType.Album)
  244.         else (n - n1 - n2, EntityType.Song)
  245.       val eid = et match {
  246.         case EntityType.Artist ⇒ sws.artistMap(keys1(i)).getId
  247.         case EntityType.Album ⇒ sws.albumMap(keys2(i)).getId
  248.         case EntityType.Song ⇒ sws.trackMap(keys3(i)).getId
  249.       }
  250.       val ct = new CrawlerTask()
  251.       ct.setProvider(Provider.Spotify)
  252.       ct.setExternalId(eid)
  253.       ct.setEntityType(et)
  254.       ct
  255.     }
  256.   }
  257.  
  258.   def ids(cts: Seq[CrawlerTask]): Seq[String] =
  259.     cts.map(_.getExternalId)
  260.  
  261.   trait SpotifyWS {
  262.     def getArtists(ids: Seq[String]): Seq[Artist]
  263.  
  264.     def getAlbums(ids: Seq[String]): Seq[Album]
  265.  
  266.     def getTracks(ids: Seq[String]): Seq[Track]
  267.   }
  268.  
  269.   class RxWrapper(sws: SpotifyWS) {
  270.     def obsArtists(ids: Seq[String]): Observable[Artist] = Observable.from(sws.getArtists(ids))
  271.  
  272.     def obsAlbums(ids: Seq[String]): Observable[Album] = Observable.from(sws.getAlbums(ids))
  273.  
  274.     def obsTracks(ids: Seq[String]): Observable[Track] = Observable.from(sws.getTracks(ids))
  275.   }
  276.  
  277.   class SpotifyWSImpl(ru: RandomUtil) extends SpotifyWS {
  278.     val trackMap = new m.HashMap[String, Track]()
  279.     val albumMap = new m.HashMap[String, Album]()
  280.     val artistMap = new m.HashMap[String, Artist]()
  281.     // go
  282.     initMediaCollection()
  283.  
  284.     override def getArtists(ids: Seq[String]): Seq[Artist] = {
  285.       val x = ru.nextInt(100)
  286.       if (x < 10)
  287.         throw new RuntimeException("timeout:" + Integer.toString(x))
  288.       else
  289.         ids.map(artistMap.getOrElse(_, null))
  290.     }
  291.  
  292.     override def getAlbums(ids: Seq[String]): Seq[Album] = {
  293.       val x = ru.nextInt(100)
  294.       if (x < 10)
  295.         throw new RuntimeException("timeout:" + Integer.toString(x))
  296.       else
  297.         ids.map(albumMap.getOrElse(_, null))
  298.     }
  299.  
  300.     override def getTracks(ids: Seq[String]): Seq[Track] = {
  301.       val x = ru.nextInt(100)
  302.       if (x < 10)
  303.         throw new RuntimeException("timeout:" + Integer.toString(x))
  304.       else
  305.         ids.map(trackMap.getOrElse(_, null))
  306.     }
  307.  
  308.     def initMediaCollection(): Unit = {
  309.       // create all
  310.       val artists = (0 until 100).map(_ ⇒ generateArtist(ru))
  311.       // let each artist to have 5 albums
  312.       // 3 exclusive, 1 with other,
  313.       // 1 with other two
  314.       // and many album-compilations where
  315.       // song is made by different artist
  316.       // e.g. album 3m6QKbHMF5GVBagWlCF1U0
  317.       val albums1 = artists.indices.flatMap({ i ⇒
  318.         val ar = artists(i)
  319.         val ars = Seq(ar)
  320.         artistMap.put(ar.getId, ar)
  321.         val al1 = generateAlbum(ru, AlbumType.SINGLE, ars)
  322.         val al2 = generateAlbum(ru, AlbumType.SINGLE, ars)
  323.         val al3 = generateAlbum(ru, AlbumType.SINGLE, ars)
  324.         Seq(al1, al2, al3)
  325.       }).toBuffer
  326.  
  327.       util.Random.shuffle(artists)
  328.  
  329.       val albums2 = artists.view.indices.drop(1).map({ i ⇒
  330.         val ars = Seq(artists(i - 1), artists(i))
  331.         generateAlbum(ru, AlbumType.ALBUM, ars)
  332.       })
  333.       // create albums of triples
  334.       util.Random.shuffle(artists)
  335.       val albums3 = artists.view.indices.drop(2).map({ i ⇒
  336.         val ars = Seq(
  337.           artists(i - 2),
  338.           artists(i - 1),
  339.           artists(i)
  340.         )
  341.         generateAlbum(ru, AlbumType.ALBUM, ars)
  342.       })
  343.       // create compilations,
  344.       // albums where the artist is "Various Artist"
  345.       val albums4 = (0 until 200).view.map({ i ⇒
  346.         generateAlbum(ru, AlbumType.COMPILATION, Seq(va))
  347.       })
  348.       // glue all the stuff together
  349.       val albums = albums1 ++ albums2 ++ albums3 ++ albums4
  350.  
  351.       // now create tracks, let each album has 10 tracks
  352.       val tracks = albums.flatMap(al ⇒
  353.         (1 to 10).map(generateTrack(ru, al, _)))
  354.  
  355.       // now put the stuff into the maps
  356.       artists.foreach(ar ⇒ artistMap.put(ar.getId, ar))
  357.       albums.foreach(al ⇒ albumMap.put(al.getId, al))
  358.       tracks.foreach(t ⇒ trackMap.put(t.getId, t))
  359.     }
  360.   }
  361.  
  362.   def run(): Unit = {
  363.  
  364.     val sws = new SpotifyWSImpl(ru)
  365.     val rxw = new RxWrapper(sws)
  366.  
  367.     val tasks = randomTasks(ru, sws, 10)
  368.     Observable.from(tasks)
  369.         .filter(ct ⇒ ct.getEntityType == EntityType.Song)
  370.         .tumblingBuffer(2)
  371.         .flatMap(cts ⇒ rxw.obsTracks(ids(cts)))
  372.         .flatMap(t ⇒ {
  373.           // we got track, now we want the artists and album from it
  374.           // val artists = t.getArtists
  375.           // val album = t.getAlbum
  376.           Observable.just(t)
  377.         })
  378.         .subscribe(t ⇒ println(t))
  379.   }
  380.  
  381.   run()
  382. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement