func ShowEpisodeLinks(ctx *gin.Context) { seasonNumber, _ := strconv.Atoi(ctx.Params.ByName("season")) episodeNumber, _ := strconv.Atoi(ctx.Params.ByName("episode")) torrents, err := showEpisodeLinks(ctx.Params.ByName("showId"), seasonNumber, episodeNumber) if err != nil { ctx.Error(err) return } if len(torrents) == 0 { xbmc.Notify("Pulsar", "No links were found", config.AddonIcon()) return } choices := make([]string, 0, len(torrents)) for _, torrent := range torrents { label := fmt.Sprintf("S:%d P:%d - %s", torrent.Seeds, torrent.Peers, torrent.Name, ) choices = append(choices, label) } choice := xbmc.ListDialog("Choose stream", choices...) if choice >= 0 { rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[choice].Magnet()) ctx.Redirect(302, rUrl) } }
func main() { // Make sure we are properly multithreaded. runtime.GOMAXPROCS(runtime.NumCPU()) logging.SetFormatter(logging.MustStringFormatter("%{time:2006-01-02 15:04:05} %{level:.4s} %{module:-15s} %{message}")) logging.SetBackend(logging.NewLogBackend(os.Stdout, "", 0)) for _, line := range strings.Split(PulsarLogo, "\n") { log.Info(line) } log.Info("Version: %s Git: %s Go: %s", util.Version, util.GitCommit, runtime.Version()) conf := config.Reload() ensureSingleInstance() Migrate() xbmc.CloseAllDialogs() log.Info("Addon: %s v%s", conf.Info.Id, conf.Info.Version) btService := bittorrent.NewBTService(*makeBTConfiguration(conf)) var shutdown = func() { log.Info("Shutting down...") btService.Close() log.Info("Bye bye") os.Exit(0) } var watchParentProcess = func() { for { // did the parent die? shutdown! if os.Getppid() == 1 { log.Warning("Parent shut down. Me too.") go shutdown() break } time.Sleep(1 * time.Second) } } go watchParentProcess() http.Handle("/", api.Routes(btService)) http.Handle("/files/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := http.StripPrefix("/files/", http.FileServer(bittorrent.NewTorrentFS(btService, config.Get().DownloadPath))) handler.ServeHTTP(w, r) })) http.Handle("/reload", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { btService.Reconfigure(*makeBTConfiguration(config.Reload())) })) http.Handle("/shutdown", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { shutdown() })) xbmc.Notify("Pulsar", "Pulsar daemon has started", config.AddonIcon()) http.ListenAndServe(":"+strconv.Itoa(config.ListenPort), nil) }
func MoviePlay(ctx *gin.Context) { torrents := movieLinks(ctx.Params.ByName("imdbId")) if len(torrents) == 0 { xbmc.Notify("Pulsar", "No links were found", config.AddonIcon()) return } sort.Sort(sort.Reverse(providers.ByQuality(torrents))) rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[0].Magnet()) ctx.Redirect(302, rUrl) }
func movieLinks(imdbId string) []*bittorrent.Torrent { log.Println("Searching links for IMDB:", imdbId) movie := tmdb.GetMovieFromIMDB(imdbId, config.Get().Language) log.Printf("Resolved %s to %s\n", imdbId, movie.Title) searchers := providers.GetMovieSearchers() if len(searchers) == 0 { xbmc.Notify("Pulsar", "Unable to find any providers", config.AddonIcon()) } return providers.SearchMovie(searchers, movie) }
func ShowEpisodePlay(ctx *gin.Context) { seasonNumber, _ := strconv.Atoi(ctx.Params.ByName("season")) episodeNumber, _ := strconv.Atoi(ctx.Params.ByName("episode")) torrents, err := showEpisodeLinks(ctx.Params.ByName("showId"), seasonNumber, episodeNumber) if err != nil { ctx.Error(err) return } if len(torrents) == 0 { xbmc.Notify("Pulsar", "No links were found", config.AddonIcon()) return } rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[0].Magnet()) ctx.Redirect(302, rUrl) }
func showEpisodeLinks(showId string, seasonNumber, episodeNumber int) ([]*bittorrent.Torrent, error) { log.Println("Searching links for TVDB Id:", showId) show, err := tvdb.NewShowCached(showId, config.Get().Language) if err != nil { return nil, err } episode := show.Seasons[seasonNumber].Episodes[episodeNumber-1] log.Printf("Resolved %s to %s\n", showId, show.SeriesName) searchers := providers.GetEpisodeSearchers() if len(searchers) == 0 { xbmc.Notify("Pulsar", "Unable to find any providers", config.AddonIcon()) } return providers.SearchEpisode(searchers, show, episode), nil }
func MovieLinks(ctx *gin.Context) { torrents := movieLinks(ctx.Params.ByName("imdbId")) if len(torrents) == 0 { xbmc.Notify("Pulsar", "No links were found", config.AddonIcon()) return } choices := make([]string, 0, len(torrents)) for _, torrent := range torrents { info := make([]string, 0) if torrent.RipType > 0 { info = append(info, bittorrent.Rips[torrent.RipType]) } if torrent.Resolution > 0 { info = append(info, bittorrent.Resolutions[torrent.Resolution]) } if torrent.VideoCodec > 0 { info = append(info, bittorrent.Codecs[torrent.VideoCodec]) } if torrent.AudioCodec > 0 { info = append(info, bittorrent.Codecs[torrent.AudioCodec]) } label := fmt.Sprintf("S:%d P:%d - %s - %s", torrent.Seeds, torrent.Peers, strings.Join(info, " "), torrent.Name, ) choices = append(choices, label) } choice := xbmc.ListDialog("Choose stream", choices...) if choice >= 0 { rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[choice].Magnet()) ctx.Redirect(302, rUrl) } }
func (btp *BTPlayer) onMetadataReceived() { btp.log.Info("Metadata received.") btp.torrentHandle.Pause() defer btp.torrentHandle.Resume() btp.torrentName = btp.torrentHandle.Status(uint(0)).GetName() go ga.TrackEvent("player", "metadata_received", btp.torrentName, -1) btp.torrentInfo = btp.torrentHandle.Torrent_file() if btp.diskStatus != nil { btp.log.Info("Checking for sufficient space on %s...", btp.bts.config.DownloadPath) torrentSize := btp.torrentInfo.Total_size() if btp.diskStatus.Free < torrentSize { btp.log.Info("Unsufficient free space on %s. Has %d, needs %d.", btp.bts.config.DownloadPath, btp.diskStatus.Free, torrentSize) xbmc.Notify("Pulsar", "Not enough space available on the download path.", config.AddonIcon()) btp.bufferEvents.Broadcast(errors.New("Not enough space on download destination.")) return } } btp.biggestFile = btp.findBiggestFile() btp.log.Info("Biggest file: %s", btp.biggestFile.GetPath()) btp.log.Info("Setting piece priorities") pieceLength := float64(btp.torrentInfo.Piece_length()) startPiece, endPiece, _ := btp.getFilePiecesAndOffset(btp.biggestFile) startLength := float64(endPiece-startPiece) * float64(pieceLength) * startBufferPercent if startLength < startBufferMinSize { startLength = startBufferMinSize } startBufferPieces := int(math.Ceil(startLength / pieceLength)) // Prefer a fixed size, since metadata are very rarely over endPiecesSize=10MB // anyway. endBufferPieces := int(math.Ceil(float64(endBufferSize) / pieceLength)) piecesPriorities := libtorrent.NewStd_vector_int() defer libtorrent.DeleteStd_vector_int(piecesPriorities) btp.bufferPiecesProgressLock.Lock() defer btp.bufferPiecesProgressLock.Unlock() // Properly set the pieces priority vector curPiece := 0 for _ = 0; curPiece < startPiece; curPiece++ { piecesPriorities.Add(0) } for _ = 0; curPiece < startPiece+startBufferPieces; curPiece++ { // get this part piecesPriorities.Add(1) btp.bufferPiecesProgress[curPiece] = 0 btp.torrentHandle.Set_piece_deadline(curPiece, 0, 0) } for _ = 0; curPiece < endPiece-endBufferPieces; curPiece++ { piecesPriorities.Add(1) } for _ = 0; curPiece <= endPiece; curPiece++ { // get this part piecesPriorities.Add(7) btp.bufferPiecesProgress[curPiece] = 0 btp.torrentHandle.Set_piece_deadline(curPiece, 0, 0) } numPieces := btp.torrentInfo.Num_pieces() for _ = 0; curPiece < numPieces; curPiece++ { piecesPriorities.Add(0) } btp.torrentHandle.Prioritize_pieces(piecesPriorities) }
func ClearCache(ctx *gin.Context) { os.RemoveAll(filepath.Join(config.Get().Info.Profile, "cache")) xbmc.Notify("Pulsar", "Cache cleared", config.AddonIcon()) }