Skip to content

Instantly share code, notes, and snippets.

@0xFEEDC0DE64
Last active March 28, 2017 08:24
Show Gist options
  • Save 0xFEEDC0DE64/a4414914faec170bd9389be95f9d1696 to your computer and use it in GitHub Desktop.
Save 0xFEEDC0DE64/a4414914faec170bd9389be95f9d1696 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using Newtonsoft.Json;
namespace BsToLib
{
class BsToWebClient : WebClient
{
private string publicKey;
private string privateKey;
private string cacheDir;
private TimeSpan maxCacheTime;
private HashAlgorithm hashAlgorithm;
private DateTime lastBsToRequest;
public class SeriesResponse : List<SeriesResponse.Serie>
{
public class Serie
{
public string id;
public string series;
}
}
public class SeriesGenreResponse : Dictionary<string, SeriesGenreResponse.Genre>
{
public class Genre
{
public class Serie
{
public int id;
public string name;
}
public int id;
public List<Serie> series;
}
}
public class SerieResponse
{
public class Serie
{
public class Data
{
public List<string> actor;
public List<string> author;
public List<string> genre;
public List<string> director;
public List<string> producer;
public string genre_main;
}
public string id;
public string series;
public string url;
public string description;
public string start;
public string end;
public string movies;
public string seasons;
public Data data;
}
public Serie series;
}
public class SeasonResponse
{
public class Episode
{
public string epi;
public string german;
public string english;
public string watched;
}
public int season;
public List<Episode> epi;
}
public class EpisodeResponse
{
public class Episode
{
public string id;
public string german;
public string english;
public string description;
}
public class Link
{
public string id;
public string hoster;
}
public string series;
public Episode epi;
public List<Link> links;
}
public class LinkResponse
{
public string epi;
public string hoster;
public string url;
public string fullurl;
}
public BsToWebClient(string publicKey = "OXI1L47qvWohTqVRjdGVwsocuOkeaRbL", string privateKey = "Gh86wdxreHBl0kMLFoMOzbv75kZt0UiG", string cacheDir = "bs.to-cache")
{
this.publicKey = publicKey;
this.privateKey = privateKey;
this.cacheDir = cacheDir;
this.maxCacheTime = new TimeSpan(7, 0, 0, 0); //TODO: make this an optional argument
hashAlgorithm = new HMACSHA256(Encoding.Default.GetBytes(privateKey));
lastBsToRequest = new DateTime();
if (!Directory.Exists(cacheDir))
Directory.CreateDirectory(cacheDir);
}
protected override WebRequest GetWebRequest(Uri url)
{
var webRequest = (HttpWebRequest)base.GetWebRequest(url);
if ((url.Host == "bs.to" || url.Host == "www.bs.to") && url.AbsolutePath.StartsWith("/api/"))
{
var msecsSinceLast = (DateTime.Now - lastBsToRequest).TotalMilliseconds;
if (msecsSinceLast <= 1000)
Thread.Sleep(1000 - (int)msecsSinceLast);
lastBsToRequest = DateTime.Now;
long timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds() / 1000;
var str = timestamp + url.AbsolutePath.Substring(4);
var bytes = Encoding.Default.GetBytes(str);
var hash = hashAlgorithm.ComputeHash(bytes);
var hashAsHex = BitConverter.ToString(hash).Replace("-", "");
var json = JsonConvert.SerializeObject(new { public_key = publicKey, timestamp = timestamp, hmac = hashAsHex });
var jsonBytes = Encoding.Default.GetBytes(json);
var base64 = Convert.ToBase64String(jsonBytes);
webRequest.Headers.Add("BS-Token", base64);
webRequest.UserAgent = "BSNova";
webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
}
return webRequest;
}
private T GetResponse<T>(string url, string cacheFilename)
{
var cachePath = Path.Combine(cacheDir, cacheFilename);
if (!File.Exists(cachePath) || DateTime.Now - File.GetLastWriteTime(cachePath) > maxCacheTime)
DownloadFile("https://www.bs.to/api/" + url, cachePath);
return JsonConvert.DeserializeObject<T>(File.ReadAllText(cachePath));
}
public SeriesResponse GetSeries()
{
return GetResponse<SeriesResponse>("series", "series.json");
}
public SeriesGenreResponse GetSeriesGenre()
{
return GetResponse<SeriesGenreResponse>("series:genre", "series_genre.json");
}
public SerieResponse GetSerie(int id)
{
return GetResponse<SerieResponse>(string.Format("series/{0}/1", id), string.Format("series_{0}_1.json", id));
}
public SeasonResponse GetSeason(int id, int season)
{
return GetResponse<SeasonResponse>(string.Format("series/{0}/{1}", id, season), string.Format("series_{0}_{1}.json", id, season));
}
public EpisodeResponse GetEpisode(int id, int season, int episode)
{
return GetResponse<EpisodeResponse>(string.Format("series/{0}/{1}/{2}", id, season, episode), string.Format("series_{0}_{1}_{2}.json", id, season, episode));
}
public LinkResponse GetLink(int id)
{
return GetResponse<LinkResponse>(string.Format("watch/{0}", id), string.Format("watch_{0}.json", id));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment