public R <PlayResource, LocalStr> GetResourceById(ResolveContext ctx, AudioResource resource) { var result = ValidateFromString(ctx.Config, resource.ResourceId); if (!result) { return(result.Error); } var resData = result.Value; if (resData.IsIcyStream) { if (resource.ResourceTitle == null) { resource = resource.WithTitle(StringNormalize.Normalize(resData.Title)); } return(new MediaPlayResource(resData.FullUri, resource, null, true)); } if (resource.ResourceTitle == null) { resource = resource.WithTitle(!string.IsNullOrWhiteSpace(resData.Title) ? StringNormalize.Normalize(resData.Title) : resource.ResourceId); } return(new MediaPlayResource(resData.FullUri, resource, resData.Image, false)); }
public PlayResource(string uri, AudioResource baseData, PlayInfo?playInfo = null, SongInfo?songInfo = null) { AudioResource = baseData; PlayUri = uri; PlayInfo = playInfo; SongInfo = songInfo; }
public RResultCode GetResourceById(string id, string name, out AudioResource resource) { string finalRequest = $"https://api.soundcloud.com/tracks/{id}/stream?client_id={SoundcloudClientID}"; resource = new SoundcloudResource(id, name, finalRequest); return(RResultCode.Success); }
private R <PlayResource, LocalStr> GetResourceById(AudioResource resource, bool allowNullName) { if (SoundcloudLink.IsMatch(resource.ResourceId)) { return(GetResource(resource.ResourceId)); } if (resource.ResourceTitle is null) { if (!allowNullName) { return(new LocalStr(strings.error_media_internal_missing + " (title)")); } string link = RestoreLink(resource.ResourceId); if (link is null) { return(new LocalStr(strings.error_media_internal_missing + " (link)")); } return(GetResource(link)); } string finalRequest = $"https://api.soundcloud.com/tracks/{resource.ResourceId}/stream?client_id={SoundcloudClientId}"; return(new PlayResource(finalRequest, resource)); }
public R <PlayResource, LocalStr> GetResourceById(ResolveContext _, AudioResource resource) { var result = DownloadEmbeddedSite(resource.ResourceId); if (!result.Ok) { return(result.Error); } var webSite = result.Value; if (resource.ResourceTitle == null) { var nameMatch = TrackNameRegex.Match(webSite); resource = resource.WithTitle(nameMatch.Success ? StringNormalize.Normalize(nameMatch.Groups[1].Value) : $"Bandcamp (id: {resource.ResourceId})"); } var match = TrackLinkRegex.Match(webSite); if (!match.Success) { return(new LocalStr(strings.error_media_internal_missing + " (TrackLinkRegex)")); } return(new BandcampPlayResource(match.Groups[1].Value, resource, GetTrackArtId(webSite))); }
public R <PlayResource, LocalStr> GetResource(ResolveContext ctx, string uriOrUrl) { string uri; // Convert if it is a URL. var uriResult = SpotifyApi.UrlToUri(uriOrUrl); if (uriResult.Ok) { uri = uriResult.Value; } else { uri = uriOrUrl; } var trackOption = api.UriToTrack(uri); if (!trackOption.Ok) { return(trackOption.Error); } var resource = new AudioResource(uri, SpotifyApi.TrackToName(trackOption.Value), ResolverFor); return(new PlayResource(resource.ResourceId, resource)); }
public R <PlayResource, LocalStr> GetResourceById(AudioResource resource) { var result = ValidateFromString(resource.ResourceId); if (!result) { return(result.Error); } var resData = result.Value; if (resData.IsIcyStream) { resource.ResourceTitle = resData.Title; return(new MediaPlayResource(resData.FullUri, resource, null, true)); } if (resource.ResourceTitle == null) { if (!string.IsNullOrWhiteSpace(resData.Title)) { resource.ResourceTitle = resData.Title; } else { resource.ResourceTitle = resource.ResourceId; } } return(new MediaPlayResource(resData.FullUri, resource, resData.Image, false)); }
public R <PlayResource> GetResourceById(AudioResource resource) { var result = DownloadEmbeddedSite(resource.ResourceId); if (!result.Ok) { return(result.Error); } var webSite = result.Value; if (string.IsNullOrEmpty(resource.ResourceTitle)) { var nameMatch = TrackNameRegex.Match(webSite); resource.ResourceTitle = nameMatch.Success ? nameMatch.Groups[1].Value : $"Bandcamp (id: {resource.ResourceId})"; } var match = TrackLinkRegex.Match(webSite); if (!match.Success) { return("Could not extract track link"); } return(new BandcampPlayResource(match.Groups[1].Value, resource, GetTrackArtId(webSite))); }
public R <PlayResource> GetResourceById(AudioResource resource) { var result = ValidateUri(resource.ResourceId); if (!result) { return(result.Error); } else { var resData = result.Value; AudioResource finalResource; if (resource.ResourceTitle != null) { finalResource = resource; } else if (!string.IsNullOrWhiteSpace(resData.Title)) { finalResource = resource.WithName(resData.Title); } else { finalResource = resource.WithName(resource.ResourceId); } return(new PlayResource(resData.FullUri, finalResource)); } }
private R <PlayResource> GetResourceById(AudioResource resource, bool allowNullName) { if (SoundcloudLink.IsMatch(resource.ResourceId)) { return(GetResource(resource.ResourceId)); } if (resource.ResourceTitle == null) { if (!allowNullName) { return("Could not restore null title."); } string link = RestoreLink(resource.ResourceId); if (link == null) { return("Could not restore link from id"); } return(GetResource(link)); } string finalRequest = $"https://api.soundcloud.com/tracks/{resource.ResourceId}/stream?client_id={SoundcloudClientId}"; return(new PlayResource(finalRequest, resource)); }
private static R <PlayResource, LocalStr> ParseLiveData(AudioResource resource, JsonPlayerResponse parsed) { var webListResponse = WebWrapper.GetResponse(new Uri(parsed.streamingData.hlsManifestUrl), response => { return(AudioTags.M3uReader.TryGetData(response.GetResponseStream()).OkOr(null)); }); if (webListResponse.Ok) { const string AacHe = "mp4a.40.5"; const string AacLc = "mp4a.40.2"; var webList = webListResponse.Value; var streamPref = from item in webList let codecs = item.StreamMeta != null?StreamCodecMatch.Match(item.StreamMeta).Groups[1].Value : "" let codecPref = codecs.Contains(AacLc) ? 0 : codecs.Contains(AacHe) ? 1 : 2 let bitrate = item.StreamMeta != null?int.Parse(StreamBitrateMatch.Match(item.StreamMeta).Groups[1].Value) : int.MaxValue orderby codecPref, bitrate ascending select item; var streamSelect = streamPref.FirstOrDefault(); if (streamSelect != null) { if (resource.ResourceTitle == null) { resource.ResourceTitle = parsed.videoDetails.title; } return(new PlayResource(streamSelect.TrackUrl, resource)); } } return(new LocalStr(strings.error_media_no_stream_extracted)); }
public R <PlayResource, LocalStr> GetResourceById(AudioResource resource) { var result = DownloadEmbeddedSite(resource.ResourceId); if (!result.Ok) { return(result.Error); } var webSite = result.Value; if (string.IsNullOrEmpty(resource.ResourceTitle)) { var nameMatch = TrackNameRegex.Match(webSite); resource.ResourceTitle = nameMatch.Success ? nameMatch.Groups[1].Value : $"Bandcamp (id: {resource.ResourceId})"; } var match = TrackLinkRegex.Match(webSite); if (!match.Success) { return(new LocalStr(strings.error_media_internal_missing + " (TrackLinkRegex)")); } return(new BandcampPlayResource(match.Groups[1].Value, resource, GetTrackArtId(webSite))); }
public bool ReallyEquals(AudioResource other) { if (ReferenceEquals(null, other)) { return(false); } if (ReferenceEquals(this, other)) { return(true); } if (!Equals(other) || Gain != other.Gain || TitleIsUserSet != other.TitleIsUserSet) { return(false); } if (AdditionalData == null && other.AdditionalData != null) { return(false); } if (AdditionalData != null && other.AdditionalData == null) { return(false); } // Both are null (see checks above). If I use &&, static code analysis is unhappy for some weird reason. if (AdditionalData == null || other.AdditionalData == null) { return(true); } if (AdditionalData.Count != other.AdditionalData.Count) { return(false); } if (new HashSet <string>(AdditionalData.Keys).Equals(new HashSet <string>(other.AdditionalData.Keys))) { // Key sets are not the same. return(false); } foreach (var key in AdditionalData.Keys) { if (AdditionalData[key] != other.AdditionalData[key]) { // There is a key-value-pair that does not match. return(false); } } // No need to compare values in the other direction as the key sets are the same. return(true); }
public RResultCode GetResource(string url, out AudioResource resource) { var match = twitchMatch.Match(url); if (!match.Success) { resource = null; return RResultCode.TwitchInvalidUrl; } return GetResourceById(match.Groups[3].Value, null, out resource); }
public RResultCode GetResource(string ytLink, out AudioResource result) { Match matchYtId = idMatch.Match(ytLink); if (!matchYtId.Success) { result = null; return RResultCode.YtIdNotFound; } return GetResourceById(matchYtId.Groups[3].Value, null, out result); }
public R <PlayResource> GetResourceById(AudioResource resource) { var result = ResolveResourceInternal(resource); if (result.Ok) { return(result); } return(YoutubeDlWrapped(resource)); }
public RResultCode GetResource(string url, out AudioResource resource) { var match = twitchMatch.Match(url); if (!match.Success) { resource = null; return(RResultCode.TwitchInvalidUrl); } return(GetResourceById(match.Groups[3].Value, null, out resource)); }
public RResultCode GetResource(string ytLink, out AudioResource result) { Match matchYtId = idMatch.Match(ytLink); if (!matchYtId.Success) { result = null; return(RResultCode.YtIdNotFound); } return(GetResourceById(matchYtId.Groups[3].Value, null, out result)); }
public R <PlayResource, LocalStr> GetResourceById(ResolveContext ctx, AudioResource resource) { // Check if the track is available on the market of the bots spotify account. var trackOption = api.UriToTrack(resource.ResourceId); if (!trackOption.Ok) { return(trackOption.Error); } return(new PlayResource(resource.ResourceId, resource)); }
public string RestoreLink(ResolveContext _, AudioResource resource) { var artistName = resource.Get(AddArtist); var trackName = resource.Get(AddTrack); if (artistName != null && trackName != null) { return($"https://soundcloud.com/{artistName}/{trackName}"); } return("https://soundcloud.com"); }
public string RestoreLink(ResolveContext _, AudioResource resource) { var artistName = resource.Get(AddArtist); var trackName = resource.Get(AddTrack); if (artistName != null && trackName != null) { return($"https://{artistName}.bandcamp.com/track/{trackName}"); } // backup when something's wrong with the website return($"https://bandcamp.com/EmbeddedPlayer/v=2/track={resource.ResourceId}"); }
public RResultCode GetResource(string link, out AudioResource resource) { string jsonResponse; var uri = new Uri($"https://api.soundcloud.com/resolve.json?url={Uri.EscapeUriString(link)}&client_id={SoundcloudClientID}"); if (!WebWrapper.DownloadString(out jsonResponse, uri)) { resource = null; return RResultCode.ScInvalidLink; } var parsedDict = ParseJson(jsonResponse); int id = (int)parsedDict["id"]; string title = (string)parsedDict["title"]; return GetResourceById(id.ToString(), title, out resource); }
public RResultCode GetResourceById(string id, string name, out AudioResource resource) { var result = ValidateUri(id, ref name, id); if (result == RResultCode.MediaNoWebResponse) { resource = null; return(result); } else { resource = new MediaResource(id, name, id, result); return(RResultCode.Success); } }
public RResultCode GetResourceById(string id, string name, out AudioResource resource) { var result = ValidateUri(id, ref name, id); if (result == RResultCode.MediaNoWebResponse) { resource = null; return result; } else { resource = new MediaResource(id, name, id, result); return RResultCode.Success; } }
public RResultCode GetResource(string link, out AudioResource resource) { string jsonResponse; var uri = new Uri($"https://api.soundcloud.com/resolve.json?url={Uri.EscapeUriString(link)}&client_id={SoundcloudClientID}"); if (!WebWrapper.DownloadString(out jsonResponse, uri)) { resource = null; return(RResultCode.ScInvalidLink); } var parsedDict = ParseJson(jsonResponse); int id = (int)parsedDict["id"]; string title = (string)parsedDict["title"]; return(GetResourceById(id.ToString(), title, out resource)); }
// Load lookup stages // PlayResource != null => ret PlayResource // ResourceData != null => call RF.RestoreFromId // TextMessage != null => call RF.GetResoruce // else => ret Error /// <summary>Generates a new <see cref="PlayResource"/> which can be played.</summary> /// <param name="resource">An <see cref="AudioResource"/> with at least /// <see cref="AudioResource.AudioType"/> and<see cref="AudioResource.ResourceId"/> set.</param> /// <returns>The playable resource if successful, or an error message otherwise.</returns> public R <PlayResource> Load(AudioResource resource) { if (resource == null) { throw new ArgumentNullException(nameof(resource)); } IResourceFactory factory = GetFactoryFor(resource.AudioType); var result = factory.GetResourceById(resource); if (!result) { return($"Could not load ({result.Message})"); } return(result); }
private R <PlayResource> YoutubeDlWrapped(AudioResource resource) { string title = null; string url = null; Log.Write(Log.Level.Debug, "YT Ruined!"); var result = YoutubeDlHelper.FindAndRunYoutubeDl(resource.ResourceId); if (!result.Ok) { return(result.Message); } var response = result.Value; title = response.Item1; var urlOptions = response.Item2; if (urlOptions.Count == 1) { url = urlOptions[0]; } else if (urlOptions.Count >= 1) { Uri[] uriList = urlOptions.Select(s => new Uri(s)).ToArray(); Uri bestMatch = uriList .FirstOrDefault(u => HttpUtility.ParseQueryString(u.Query) .GetValues("mime") .Any(x => x.StartsWith("audio", StringComparison.OrdinalIgnoreCase))); url = (bestMatch ?? uriList[0]).OriginalString; } if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(url)) { return("No youtube-dl response"); } Log.Write(Log.Level.Debug, "YT Saved!"); return(new PlayResource(url, resource.WithName(title))); }
public async Task <PlayResource> GetResourceById(ResolveContext _, AudioResource resource) { var webSite = await DownloadEmbeddedSite(resource.ResourceId); if (string.IsNullOrEmpty(resource.ResourceTitle)) { var nameMatch = TrackNameRegex.Match(webSite); resource.ResourceTitle = nameMatch.Success ? nameMatch.Groups[1].Value : $"Bandcamp (id: {resource.ResourceId})"; } var match = TrackLinkRegex.Match(webSite); if (!match.Success) { throw Error.LocalStr(strings.error_media_internal_missing + " (TrackLinkRegex)"); } return(new BandcampPlayResource(match.Groups[1].Value, resource, GetTrackArtId(webSite))); }
private static R <PlayResource, LocalStr> YoutubeDlWrapped(AudioResource resource) { Log.Debug("Falling back to youtube-dl!"); var result = YoutubeDlHelper.FindAndRunYoutubeDl(resource.ResourceId); if (!result.Ok) { return(result.Error); } var response = result.Value; var title = response.title; var urlOptions = response.links; string url = null; if (urlOptions.Count == 1) { url = urlOptions[0]; } else if (urlOptions.Count >= 1) { Uri[] uriList = urlOptions.Select(s => new Uri(s)).ToArray(); Uri bestMatch = uriList .FirstOrDefault(u => ParseQueryString(u.Query).TryGetValue("mime", out var mimes) && mimes.Any(x => x.StartsWith("audio", StringComparison.OrdinalIgnoreCase))); url = (bestMatch ?? uriList[0]).OriginalString; } if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(url)) { return(new LocalStr(strings.error_ytdl_empty_response)); } resource.ResourceTitle = title; Log.Debug("youtube-dl succeeded!"); return(new PlayResource(url, resource)); }
public async Task <PlayResource> GetResourceById(ResolveContext ctx, AudioResource resource) { var resData = await ValidateFromString(ctx.Config, resource.ResourceId); if (resData.IsIcyStream) { resource.ResourceTitle = resData.Title; return(new MediaPlayResource(resData.FullUri, resource, null, true)); } if (resource.ResourceTitle is null) { if (!string.IsNullOrWhiteSpace(resData.Title)) { resource.ResourceTitle = resData.Title; } else { resource.ResourceTitle = resource.ResourceId; } } return(new MediaPlayResource(resData.FullUri, resource, resData.Image, false)); }
public RResultCode GetResource(string uri, out AudioResource resource) { return GetResourceById(uri, null, out resource); }
public BandcampPlayResource(string uri, AudioResource baseData, string artId) : base(uri, baseData) { ArtId = artId; }
public void AddResource(AudioResource resource) { if (!resourceSet.Contains(resource)) { Length++; } }
public string RestoreLink(ResolveContext ctx, AudioResource resource) { return(SpotifyApi.UriToUrl(resource.ResourceId).OkOr(null)); }
public void RemoveResource(AudioResource resource) { if (!resourceSet.Contains(resource)) { } }
public RResultCode GetResourceById(string id, string name, out AudioResource resource) { var channel = id; // request api token string jsonResponse; if (!WebWrapper.DownloadString(out jsonResponse, new Uri($"http://api.twitch.tv/api/channels/{channel}/access_token"))) { resource = null; return RResultCode.NoConnection; } var jsonDict = (Dictionary<string, object>)jsonParser.DeserializeObject(jsonResponse); // request m3u8 file var token = Uri.EscapeUriString(jsonDict["token"].ToString()); var sig = jsonDict["sig"]; // guaranteed to be random, chosen by fair dice roll. var random = 4; string m3u8; if (!WebWrapper.DownloadString(out m3u8, new Uri($"http://usher.twitch.tv/api/channel/hls/{channel}.m3u8?player=twitchweb&&token={token}&sig={sig}&allow_audio_only=true&allow_source=true&type=any&p={random}"))) { resource = null; return RResultCode.NoConnection; } // parse m3u8 file var dataList = new List<StreamData>(); using (var reader = new System.IO.StringReader(m3u8)) { var header = reader.ReadLine(); if (string.IsNullOrEmpty(header) || header != "#EXTM3U") { resource = null; return RResultCode.TwitchMalformedM3u8File; } while (true) { var blockInfo = reader.ReadLine(); if (string.IsNullOrEmpty(blockInfo)) break; var match = m3u8ExtMatch.Match(blockInfo); if (!match.Success) continue; switch (match.Groups[1].Value) { case "EXT-X-TWITCH-INFO": break; // Ignore twitch info line case "EXT-X-MEDIA": string streamInfo = reader.ReadLine(); Match infoMatch; if (string.IsNullOrEmpty(streamInfo) || !(infoMatch = m3u8ExtMatch.Match(streamInfo)).Success || infoMatch.Groups[1].Value != "EXT-X-STREAM-INF") { resource = null; return RResultCode.TwitchMalformedM3u8File; } var streamData = new StreamData(); // #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000,CODECS="mp4a.40.2",VIDEO="audio_only" for (int i = 0; i < infoMatch.Groups[3].Captures.Count; i++) { string key = infoMatch.Groups[4].Captures[i].Value.ToUpper(); string value = infoMatch.Groups[5].Captures[i].Value; switch (key) { case "BANDWIDTH": streamData.Bandwidth = int.Parse(value); break; case "CODECS": streamData.Codec = TextUtil.StripQuotes(value); break; case "VIDEO": StreamQuality quality; if (Enum.TryParse(TextUtil.StripQuotes(value), out quality)) streamData.QualityType = quality; else streamData.QualityType = StreamQuality.unknown; break; } } streamData.Url = reader.ReadLine(); dataList.Add(streamData); break; default: break; } } } resource = new TwitchResource(channel, name ?? $"Twitch channel: {channel}", dataList); return dataList.Count > 0 ? RResultCode.Success : RResultCode.TwitchNoStreamsExtracted; }
public RResultCode GetResourceById(string id, string name, out AudioResource resource) { string finalRequest = $"https://api.soundcloud.com/tracks/{id}/stream?client_id={SoundcloudClientID}"; resource = new SoundcloudResource(id, name, finalRequest); return RResultCode.Success; }
public R <PlayResource, LocalStr> GetResourceById(AudioResource resource) => GetResourceById(resource, true);
public string RestoreLink(AudioResource res) { IResourceFactory factory = GetFactoryFor(res.AudioType); return factory.RestoreLink(res.ResourceId); }
public string?RestoreLink(AudioResource res) => Resolver.RestoreLink(this, res);
public RResultCode GetResourceById(string ytID, string name, out AudioResource result) { string resulthtml; if (!WebWrapper.DownloadString(out resulthtml, new Uri($"http://www.youtube.com/get_video_info?video_id={ytID}&el=info"))) { result = null; return RResultCode.NoConnection; } var videoTypes = new List<VideoData>(); NameValueCollection dataParse = HttpUtility.ParseQueryString(resulthtml); string videoDataUnsplit = dataParse["url_encoded_fmt_stream_map"]; if (videoDataUnsplit != null) { string[] videoData = videoDataUnsplit.Split(','); foreach (string vdat in videoData) { NameValueCollection videoparse = HttpUtility.ParseQueryString(vdat); string vLink = videoparse["url"]; if (vLink == null) continue; string vType = videoparse["type"]; if (vType == null) continue; string vQuality = videoparse["quality"]; if (vQuality == null) continue; var vt = new VideoData(); vt.link = vLink; vt.codec = GetCodec(vType); vt.qualitydesciption = vQuality; videoTypes.Add(vt); } } videoDataUnsplit = dataParse["adaptive_fmts"]; if (videoDataUnsplit != null) { string[] videoData = videoDataUnsplit.Split(','); foreach (string vdat in videoData) { NameValueCollection videoparse = HttpUtility.ParseQueryString(vdat); string vType = videoparse["type"]; if (vType == null) continue; bool audioOnly = false; if (vType.StartsWith("video/")) continue; else if (vType.StartsWith("audio/")) audioOnly = true; string vLink = videoparse["url"]; if (vLink == null) continue; var vt = new VideoData(); vt.codec = GetCodec(vType); vt.qualitydesciption = vType; vt.link = vLink; if (audioOnly) vt.audioOnly = true; else vt.videoOnly = true; videoTypes.Add(vt); } } string finalName = name ?? dataParse["title"] ?? $"<YT - no title : {ytID}>"; var ytResult = new YoutubeResource(ytID, finalName, videoTypes); result = ytResult; return ytResult.AvailableTypes.Count > 0 ? RResultCode.Success : RResultCode.YtNoVideosExtracted; }