@@ -53,7 +53,7 @@ let uploadMusik (stream:Stream) = task {
5353let mapBlobMusikTag ( tag : Tag ) = task {
5454 match tag.Action with
5555 | TagAction.PlayBlobMusik mediaIDs ->
56- let list = System.Collections.Generic.List<_>()
56+ let list = System.Collections.Generic.List<_>()
5757 for mediaID in mediaIDs do
5858 let! sas = getSASMediaLink( mediaID.ToString())
5959 list.Add sas
@@ -109,7 +109,7 @@ let uploadEndpoint (userID:string) =
109109 let file = form.Files.[ 0 ]
110110 use stream = file.OpenReadStream()
111111 let! tagAction = uploadMusik stream
112- let tag : Tag = {
112+ let tag : Tag = {
113113 Token = System.Guid.NewGuid() .ToString()
114114 Action = tagAction
115115 Description = " "
@@ -130,14 +130,14 @@ let previousFileEndpoint (userID,token) =
130130 plug ( fun next ctx -> task {
131131 let! _ = AzureTable.saveRequest userID token
132132 let! tag = AzureTable.getTag userID token
133- let! position = AzureTable.getPlayListPosition userID token
133+ let! position = AzureTable.getPlayListPosition userID token
134134 let position = position |> Option.map ( fun p -> p.Position + 1 ) |> Option.defaultValue 0
135135 let! _ = AzureTable.savePlayListPosition userID token position
136136 let! tag =
137137 match tag with
138138 | Some t -> mapBlobMusikTag t
139- | _ ->
140- let t = {
139+ | _ ->
140+ let t = {
141141 Token = token
142142 UserID = userID
143143 Action = TagAction.UnknownTag
@@ -147,7 +147,7 @@ let previousFileEndpoint (userID,token) =
147147 task { return t }
148148
149149 let! tag = mapYoutube tag
150- let tag : TagForBox = {
150+ let tag : TagForBox = {
151151 Token = tag.Token
152152 Object = tag.Object
153153 Description = tag.Description
@@ -158,40 +158,145 @@ let previousFileEndpoint (userID,token) =
158158 })
159159 }
160160
161+ let accessToken = " 0df1e468-cd6f-4038-9734-9bcf4777925b"
162+ let group = " RINCON_347E5CF009E001400:3169659583"
163+
164+ open System.Net
165+ open Microsoft.Extensions .Logging
166+
167+ let post ( log : ILogger ) ( url : string ) headers ( data : string ) = task {
168+ let req = HttpWebRequest.Create( url) :?> HttpWebRequest
169+ req.ProtocolVersion <- HttpVersion.Version10
170+ req.Method <- " POST"
171+
172+ for ( name: string ),( value : string ) in headers do
173+ req.Headers.Add( name, value) |> ignore
174+
175+ let postBytes = System.Text.Encoding.UTF8.GetBytes( data)
176+ req.ContentType <- " application/json; charset=utf-8"
177+ req.ContentLength <- int64 postBytes.Length
178+
179+ try
180+ // Write data to the request
181+ use reqStream = req.GetRequestStream()
182+ do ! reqStream.WriteAsync( postBytes, 0 , postBytes.Length)
183+ reqStream.Close()
184+
185+ use resp = req.GetResponse()
186+ use stream = resp.GetResponseStream()
187+ use reader = new StreamReader( stream)
188+ let! html = reader.ReadToEndAsync()
189+ return html
190+ with
191+ | : ? WebException as exn when not ( isNull exn .Response ) ->
192+ use errorResponse = exn.Response :?> HttpWebResponse
193+ use reader = new StreamReader( errorResponse.GetResponseStream())
194+ let error = reader.ReadToEnd()
195+ log.LogError( sprintf " Request to %s failed with: %s %s " url exn.Message error)
196+ return ! raise exn
197+ }
198+
199+ type Session =
200+ { ID : string }
201+
202+ static member Decoder =
203+ Decode.object ( fun get ->
204+ { ID = get.Required.Field " sessionId" Decode.string }
205+ )
206+
207+ let createOrJoinSession ( log : ILogger ) accessToken group = task {
208+ let headers = [ " Bearer " , accessToken]
209+ let url = sprintf " https://api.ws.sonos.com/control/api/v1/groups/%s /playbackSession/joinOrCreate" group
210+ let body = """ {
211+ "appId": "com.Forkmann.AudioHub",
212+ "appContext": "1a2b3c24b",
213+ "customData": "playlistid:12345"
214+ }"""
215+
216+ let! result = post log url headers body
217+
218+ match Decode.fromString Session.Decoder result with
219+ | Error msg -> return failwith msg
220+ | Ok session -> return session
221+ }
222+
223+
224+ let playStream ( log : ILogger ) accessToken ( session : Session ) ( tag : Tag ) = task {
225+ let headers = [ " Bearer " , accessToken]
226+ let url = sprintf " https://api.ws.sonos.com/control/api/v1/playbackSessions/%s /playbackSession/loadStreamUrl" session.ID
227+
228+ match tag.Action with
229+ | TagAction.PlayMusik stream ->
230+ let body = sprintf """ {
231+ "streamUrl": "%s ",
232+ "playOnCompletion": true,
233+ "stationMetadata": {
234+ "name": "%s "
235+ },
236+ "itemId" : "%s "
237+ }""" stream.[ 0 ] ( tag.Object + " - " + tag.Description) tag.Token
238+
239+
240+ let! _result = post log url headers body
241+ ()
242+ | _ -> ()
243+ }
244+
161245let nextFileEndpoint ( userID , token ) =
162246 pipeline {
163247 set_ header " Content-Type" " application/json"
164248 plug ( fun next ctx -> task {
165249 let! _ = AzureTable.saveRequest userID token
166- let! tag = AzureTable.getTag userID token
167-
168- let! position = AzureTable.getPlayListPosition userID token
169- let position = position |> Option.map ( fun p -> p.Position - 1 ) |> Option.defaultValue 0
170-
171- let! tag =
172- match tag with
173- | Some t -> mapBlobMusikTag t
174- | _ ->
175- let t = {
176- Token = token
177- UserID = userID
178- Action = TagAction.UnknownTag
179- LastVerified = DateTimeOffset.MinValue
180- Description = " "
181- Object = " " }
182- task { return t }
183-
184- let! tag = mapYoutube tag
185- let tag : TagForBox = {
186- Token = tag.Token
187- Object = tag.Object
188- Description = tag.Description
189- Action = TagActionForBox.GetFromTagAction( tag.Action, position) }
190-
191- let! _ = AzureTable.savePlayListPosition userID token position
192-
193- let txt = TagForBox.Encoder tag |> Encode.toString 0
194- return ! setBodyFromString txt next ctx
250+ match ! AzureTable.getUser userID with
251+ | None ->
252+ return ! Response.notFound ctx userID
253+ | Some user ->
254+ let! tag = AzureTable.getTag userID token
255+
256+ let! position = AzureTable.getPlayListPosition userID token
257+ let position = position |> Option.map ( fun p -> p.Position - 1 ) |> Option.defaultValue 0
258+
259+ let! tag =
260+ match tag with
261+ | Some t -> mapBlobMusikTag t
262+ | _ ->
263+ let t = {
264+ Token = token
265+ UserID = userID
266+ Action = TagAction.UnknownTag
267+ LastVerified = DateTimeOffset.MinValue
268+ Description = " "
269+ Object = " " }
270+ task { return t }
271+
272+ let! tag = mapYoutube tag
273+ let! _ = AzureTable.savePlayListPosition userID token position
274+
275+ match user.SpeakerType with
276+ | SpeakerType.Local ->
277+ let! tag = mapYoutube tag
278+ let tag : TagForBox = {
279+ Token = tag.Token
280+ Object = tag.Object
281+ Description = tag.Description
282+ Action = TagActionForBox.GetFromTagAction( tag.Action, position) }
283+
284+
285+ let txt = TagForBox.Encoder tag |> Encode.toString 0
286+ return ! setBodyFromString txt next ctx
287+ | SpeakerType.Sonos ->
288+ let logger = ctx.GetLogger " NextFile"
289+ let! session = createOrJoinSession logger accessToken group
290+ do ! playStream logger accessToken session tag
291+
292+ let tag : TagForBox = {
293+ Token = tag.Token
294+ Object = tag.Object
295+ Description = tag.Description
296+ Action = TagActionForBox.Ignore }
297+
298+ let txt = TagForBox.Encoder tag |> Encode.toString 0
299+ return ! setBodyFromString txt next ctx
195300 })
196301 }
197302
0 commit comments