Example #1
0
func Authorize(fromSettings bool) error {
	code, err := GetCode()

	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
		return err
	}
	log.Noticef("Got code for %s: %s", code.VerificationURL, code.UserCode)

	if xbmc.Dialog("LOCALIZE[30058]", fmt.Sprintf("Visit %s and enter your code: %s", code.VerificationURL, code.UserCode)) == false {
		return errors.New("Authentication canceled.")
	}

	token, err := PollToken(code)

	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
		return err
	}

	success := "Woohoo!"
	if fromSettings {
		success += " (Save your settings!)"
	}
	xbmc.Notify("Quasar", success, config.AddonIcon())
	xbmc.SetSetting("trakt_token", token.AccessToken)
	xbmc.SetSetting("trakt_refresh_token", token.RefreshToken)
	return nil
}
Example #2
0
func GetList(listId string, language string, page int) Movies {
	var results *List
	listResultsPerPage := config.Get().ResultsPerPage

	rateLimiter.Call(func() {
		urlValues := napping.Params{
			"api_key": apiKey,
		}.AsUrlValues()
		resp, err := napping.Get(
			tmdbEndpoint+"list/"+listId,
			&urlValues,
			&results,
			nil,
		)
		if err != nil {
			log.Error(err.Error())
			xbmc.Notify("Quasar", "GetList failed, check your logs.", config.AddonIcon())
		} else if resp.Status() != 200 {
			message := fmt.Sprintf("GetList bad status: %d", resp.Status())
			log.Error(message)
			xbmc.Notify("Quasar", message, config.AddonIcon())
		}
	})
	tmdbIds := make([]int, 0, listResultsPerPage)
	for i, movie := range results.Items {
		if i < page*listResultsPerPage {
			continue
		}
		tmdbIds = append(tmdbIds, movie.Id)
		if i >= (startPage+page)*listResultsPerPage-1 {
			break
		}
	}
	return GetMovies(tmdbIds, language)
}
Example #3
0
func ListShows(endpoint string, params napping.Params, page int) (shows Shows) {
	var results *EntityList

	params["page"] = strconv.Itoa(startPage + page)
	params["api_key"] = apiKey
	p := params.AsUrlValues()

	rateLimiter.Call(func() {
		resp, err := napping.Get(
			tmdbEndpoint + endpoint,
			&p,
			&results,
			nil,
		)
		if err != nil {
			log.Error(err.Error())
			xbmc.Notify("Quasar", "ListShows failed, check your logs.", config.AddonIcon())
		} else if resp.Status() != 200 {
			message := fmt.Sprintf("ListShows bad status: %d", resp.Status())
			log.Error(message)
			xbmc.Notify("Quasar", message, config.AddonIcon())
		}
	})
	if results != nil {
		for _, show := range results.Results {
			shows = append(shows, GetShow(show.Id, params["language"]))
		}
	}
	return shows
}
Example #4
0
func SearchShows(query string, language string, page int) Shows {
	var results EntityList
	rateLimiter.Call(func() {
		urlValues := napping.Params{
			"api_key": apiKey,
			"query":   query,
			"page":    strconv.Itoa(startPage + page),
		}.AsUrlValues()
		resp, err := napping.Get(
			tmdbEndpoint+"search/tv",
			&urlValues,
			&results,
			nil,
		)
		if err != nil {
			log.Error(err.Error())
			xbmc.Notify("Quasar", "SearchShows failed, check your logs.", config.AddonIcon())
		} else if resp.Status() != 200 {
			message := fmt.Sprintf("SearchShows bad status: %d", resp.Status())
			log.Error(message)
			xbmc.Notify("Quasar", message, config.AddonIcon())
		}
	})
	tmdbIds := make([]int, 0, len(results.Results))
	for _, entity := range results.Results {
		tmdbIds = append(tmdbIds, entity.Id)
	}
	return GetShows(tmdbIds, language)
}
Example #5
0
func Find(externalId string, externalSource string) *FindResult {
	var result *FindResult

	cacheStore := cache.NewFileStore(path.Join(config.Get().ProfilePath, "cache"))
	key := fmt.Sprintf("com.tmdb.find.%s.%s", externalSource, externalId)
	if err := cacheStore.Get(key, &result); err != nil {
		rateLimiter.Call(func() {
			urlValues := napping.Params{
				"api_key":         apiKey,
				"external_source": externalSource,
			}.AsUrlValues()
			resp, err := napping.Get(
				tmdbEndpoint+"find/"+externalId,
				&urlValues,
				&result,
				nil,
			)
			if err != nil {
				log.Error(err.Error())
				xbmc.Notify("Quasar", "Failed Find call, check your logs.", config.AddonIcon())
			} else if resp.Status() != 200 {
				message := fmt.Sprintf("Find call bad status: %d", resp.Status())
				log.Error(message)
				xbmc.Notify("Quasar", message, config.AddonIcon())
			}
			cacheStore.Set(key, result, 365*24*time.Hour)
		})
	}

	return result
}
Example #6
0
func ListShowsComplete(endpoint string, params napping.Params, page int) Shows {
	maxPages := MaxPages
	if page >= 0 {
		maxPages = 1
	}
	shows := make(Shows, maxPages*resultsPerPage)

	params["api_key"] = apiKey

	wg := sync.WaitGroup{}
	for i := 0; i < maxPages; i++ {
		wg.Add(1)
		currentpage := i
		startIndex := i * resultsPerPage
		if page >= 0 {
			currentpage = page
		}
		go func(page int) {
			defer wg.Done()
			var tmp *EntityList
			tmpParams := napping.Params{
				"page": strconv.Itoa(startPage + page),
			}
			for k, v := range params {
				tmpParams[k] = v
			}
			urlValues := tmpParams.AsUrlValues()
			rateLimiter.Call(func() {
				resp, err := napping.Get(
					tmdbEndpoint+endpoint,
					&urlValues,
					&tmp,
					nil,
				)
				if err != nil {
					log.Error(err.Error())
					xbmc.Notify("Quasar", "ListShows failed, check your logs.", config.AddonIcon())
				} else if resp.Status() != 200 {
					message := fmt.Sprintf("ListShows bad status: %d", resp.Status())
					xbmc.Notify("Quasar", message, config.AddonIcon())
				}
			})
			if tmp != nil {
				for i, entity := range tmp.Results {
					shows[startIndex+i] = GetShow(entity.Id, params["language"])
				}
			}
		}(currentpage)
	}
	wg.Wait()

	return shows
}
Example #7
0
func RemoveMovieFromWatchlist(ctx *gin.Context) {
	tmdbId := ctx.Params.ByName("tmdbId")
	resp, err := trakt.RemoveFromWatchlist("movies", tmdbId)
	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
	} else if resp.Status() != 200 {
		xbmc.Notify("Quasar", fmt.Sprintf("Failed with %d status code", resp.Status()), config.AddonIcon())
	} else {
		xbmc.Notify("Quasar", "Movie removed from watchlist", config.AddonIcon())
		os.RemoveAll(filepath.Join(config.Get().Info.Profile, "cache"))
		xbmc.Refresh()
	}
}
Example #8
0
func AddMovieToCollection(ctx *gin.Context) {
	tmdbId := ctx.Params.ByName("tmdbId")
	resp, err := trakt.AddToCollection("movies", tmdbId)
	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
	} else if resp.Status() != 201 {
		xbmc.Notify("Quasar", fmt.Sprintf("Failed with %d status code", resp.Status()), config.AddonIcon())
	} else {
		xbmc.Notify("Quasar", "Movie added to collection", config.AddonIcon())
		os.RemoveAll(filepath.Join(config.Get().Info.Profile, "cache"))
		xbmc.Refresh()
	}
}
Example #9
0
func AddShowToWatchlist(ctx *gin.Context) {
	tmdbId := ctx.Params.ByName("showId")
	resp, err := trakt.AddToWatchlist("shows", tmdbId)
	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
	} else if resp.Status() != 201 {
		xbmc.Notify("Quasar", fmt.Sprintf("Failed %d", resp.Status()), config.AddonIcon())
	} else {
		xbmc.Notify("Quasar", "Show added to watchlist", config.AddonIcon())
		os.RemoveAll(filepath.Join(config.Get().Info.Profile, "cache"))
		xbmc.Refresh()
	}
}
Example #10
0
func GetShow(showId int, language string) *Show {
	var show *Show
	cacheStore := cache.NewFileStore(path.Join(config.Get().ProfilePath, "cache"))
	key := fmt.Sprintf("com.tmdb.show.%d.%s", showId, language)
	if err := cacheStore.Get(key, &show); err != nil {
		rateLimiter.Call(func() {
			urlValues := napping.Params{
				"api_key":            apiKey,
				"append_to_response": "credits,images,alternative_titles,translations,external_ids",
				"language":           language,
			}.AsUrlValues()
			resp, err := napping.Get(
				tmdbEndpoint+"tv/"+strconv.Itoa(showId),
				&urlValues,
				&show,
				nil,
			)
			if err != nil {
				switch e := err.(type) {
				case *json.UnmarshalTypeError:
					log.Errorf("UnmarshalTypeError: Value[%s] Type[%v] Offset[%d] for %d", e.Value, e.Type, e.Offset, showId)
				case *json.InvalidUnmarshalError:
					log.Errorf("InvalidUnmarshalError: Type[%v]", e.Type)
				default:
					log.Error(err.Error())
				}
				LogError(err)
				xbmc.Notify("Quasar", "GetShow failed, check your logs.", config.AddonIcon())
			} else if resp.Status() != 200 {
				message := fmt.Sprintf("GetShow bad status: %d", resp.Status())
				log.Error(message)
				xbmc.Notify("Quasar", message, config.AddonIcon())
			}
		})
		if show != nil {
			cacheStore.Set(key, show, cacheTime)
		}
	}
	if show == nil {
		return nil
	}
	switch t := show.RawPopularity.(type) {
	case string:
		if popularity, err := strconv.ParseFloat(t, 64); err == nil {
			show.Popularity = popularity
		}
	case float64:
		show.Popularity = t
	}
	return show
}
Example #11
0
func GetSeason(showId int, seasonNumber int, language string) *Season {
	var season *Season
	cacheStore := cache.NewFileStore(path.Join(config.Get().ProfilePath, "cache"))
	key := fmt.Sprintf("com.tmdb.season.%d.%d.%s", showId, seasonNumber, language)
	if err := cacheStore.Get(key, &season); err != nil {
		rateLimiter.Call(func() {
			urlValues := napping.Params{
				"api_key":            apiKey,
				"append_to_response": "credits,images,videos,external_ids",
				"language":           language,
			}.AsUrlValues()
			resp, err := napping.Get(
				fmt.Sprintf("%stv/%d/season/%d", tmdbEndpoint, showId, seasonNumber),
				&urlValues,
				&season,
				nil,
			)
			if err != nil {
				log.Error(err.Error())
				xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
			} else if resp.Status() != 200 {
				message := fmt.Sprintf("GetSeason bad status: %d", resp.Status())
				log.Error(message)
				xbmc.Notify("Quasar", message, config.AddonIcon())
			}
		})
		season.EpisodeCount = len(season.Episodes)

		// Fix for shows that have translations but return empty strings
		// for episode names and overviews.
		// We detect if episodes have their name filled, and if not re-query
		// with no language set.
		// See https://github.com/scakemyer/plugin.video.quasar/issues/249
		if season.EpisodeCount > 0 {
			for index := 0; index < season.EpisodeCount; index++ {
				if season.Episodes[index].Name == "" {
					season.Episodes[index] = GetEpisode(showId, seasonNumber, index+1, "")
				}
			}
		}

		if season != nil {
			cacheStore.Set(key, season, cacheTime)
		}
	}
	if season == nil {
		return nil
	}
	return season
}
Example #12
0
func WatchlistMovies(ctx *gin.Context) {
	movies, err := trakt.WatchlistMovies()
	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
	}
	renderTraktMovies(movies, ctx, 0)
}
Example #13
0
func ShowEpisodePlay(ctx *gin.Context) {
	tmdbId := ctx.Params.ByName("showId")
	showId, _ := strconv.Atoi(tmdbId)
	seasonNumber, _ := strconv.Atoi(ctx.Params.ByName("season"))
	episodeNumber, _ := strconv.Atoi(ctx.Params.ByName("episode"))

	show := tmdb.GetShow(showId, "")
	episode := tmdb.GetEpisode(showId, seasonNumber, episodeNumber, "")

	runtime := 45
	if len(show.EpisodeRunTime) > 0 {
		runtime = show.EpisodeRunTime[len(show.EpisodeRunTime)-1]
	}

	torrents, err := showEpisodeLinks(showId, seasonNumber, episodeNumber)
	if err != nil {
		ctx.Error(err)
		return
	}

	if len(torrents) == 0 {
		xbmc.Notify("Quasar", "LOCALIZE[30205]", config.AddonIcon())
		return
	}

	AddToTorrentsMap(strconv.Itoa(episode.Id), torrents[0])

	rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[0].Magnet(),
		"tmdb", strconv.Itoa(episode.Id),
		"type", "episode",
		"runtime", strconv.Itoa(runtime))
	ctx.Redirect(302, rUrl)
}
Example #14
0
func RemoveShow(ctx *gin.Context) {
	LibraryPath := config.Get().LibraryPath
	ShowsLibraryPath := filepath.Join(LibraryPath, "Shows")
	DBPath := filepath.Join(LibraryPath, fmt.Sprintf("%s.json", DBName))
	showId := ctx.Params.ByName("showId")
	show, err := tvdb.NewShow(showId, "en")
	if err != nil {
		ctx.String(404, "")
		return
	}
	ShowPath := filepath.Join(ShowsLibraryPath, toFileName(show.SeriesName))

	if err := RemoveFromJsonDB(DBPath, showId, LShow); err != nil {
		libraryLog.Info("Unable to remove show from db")
		ctx.String(404, "")
		return
	}

	if err := os.RemoveAll(ShowPath); err != nil {
		libraryLog.Info("Unable to remove show folder")
		ctx.String(404, "")
		return
	}

	xbmc.Notify("Quasar", "LOCALIZE[30222]", config.AddonIcon())
	ctx.String(200, "")
	xbmc.VideoLibraryClean()
	libraryLog.Info("Show removed")
}
Example #15
0
func RemoveMovie(ctx *gin.Context) {
	LibraryPath := config.Get().LibraryPath
	MoviesLibraryPath := filepath.Join(LibraryPath, "Movies")
	DBPath := filepath.Join(LibraryPath, fmt.Sprintf("%s.json", DBName))
	imdbId := ctx.Params.ByName("imdbId")
	movie := tmdb.GetMovieFromIMDB(imdbId, "en")
	MovieStrm := toFileName(fmt.Sprintf("%s (%s)", movie.OriginalTitle, strings.Split(movie.ReleaseDate, "-")[0]))
	MoviePath := filepath.Join(MoviesLibraryPath, MovieStrm)

	if err := RemoveFromJsonDB(DBPath, imdbId, LMovie); err != nil {
		libraryLog.Info("Unable to remove movie from db")
		ctx.String(404, "")
		return
	}

	if err := os.RemoveAll(MoviePath); err != nil {
		libraryLog.Info("Unable to remove movie folder")
		ctx.String(404, "")
		return
	}

	xbmc.Notify("Quasar", "LOCALIZE[30222]", config.AddonIcon())
	ctx.String(200, "")
	xbmc.VideoLibraryClean()
	libraryLog.Info("Movie removed")
}
Example #16
0
func TraktBoxOffice(ctx *gin.Context) {
	movies, err := trakt.TopMovies("boxoffice", "1")
	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
	}
	renderTraktMovies(movies, ctx, 0)
}
Example #17
0
func RemoveShow(ctx *gin.Context) {
	LibraryPath := config.Get().LibraryPath
	ShowsLibraryPath := filepath.Join(LibraryPath, "Shows")
	DBPath := filepath.Join(LibraryPath, fmt.Sprintf("%s.json", DBName))
	showId := ctx.Params.ByName("showId")
	Id, _ := strconv.Atoi(showId)
	show := tmdb.GetShow(Id, "en")
	if show == nil {
		ctx.String(404, "")
		return
	}
	ShowStrm := toFileName(fmt.Sprintf("%s (%s)", show.Name, strings.Split(show.FirstAirDate, "-")[0]))
	ShowPath := filepath.Join(ShowsLibraryPath, ShowStrm)

	if err := RemoveFromJsonDB(DBPath, showId, LShow); err != nil {
		libraryLog.Error("Unable to remove show from db")
		ctx.String(404, "")
		return
	}

	if err := os.RemoveAll(ShowPath); err != nil {
		libraryLog.Error("Unable to remove show folder")
		ctx.String(404, "")
		return
	}

	xbmc.Notify("Quasar", "LOCALIZE[30222]", config.AddonIcon())
	ctx.String(200, "")
	xbmc.VideoLibraryClean()
	ClearCache(ctx)
	xbmc.Refresh()
	libraryLog.Notice("Show removed")
}
Example #18
0
func CollectionShows(ctx *gin.Context) {
	shows, err := trakt.CollectionShows()
	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
	}
	renderTraktShows(shows, ctx, 0)
}
Example #19
0
func ProviderCheck(ctx *gin.Context) {
	addonId := ctx.Params.ByName("provider")
	failures := xbmc.AddonCheck(addonId)
	translated := xbmc.GetLocalizedString(30243)
	xbmc.Notify("Quasar", fmt.Sprintf("%s: %d", translated, failures), config.AddonIcon())
	ctx.String(200, "")
}
Example #20
0
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("Quasar", "LOCALIZE[30205]", 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("LOCALIZE[30202]", choices...)
	if choice >= 0 {
		rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[choice].Magnet())
		ctx.Redirect(302, rUrl)
	}
}
Example #21
0
func (btp *BTPlayer) addTorrent() error {
	btp.log.Info("Adding torrent")

	if btp.bts.config.DownloadPath == "." {
		xbmc.Notify("Quasar", "LOCALIZE[30113]", config.AddonIcon())
		return fmt.Errorf("Download path empty")
	}

	if status, err := diskusage.DiskUsage(btp.bts.config.DownloadPath); err != nil {
		btp.bts.log.Warningf("Unable to retrieve the free space for %s, continuing anyway...", btp.bts.config.DownloadPath)
	} else {
		btp.diskStatus = status
	}

	torrentParams := libtorrent.NewAddTorrentParams()
	defer libtorrent.DeleteAddTorrentParams(torrentParams)

	torrentParams.SetUrl(btp.uri)

	btp.log.Infof("Setting save path to %s", btp.bts.config.DownloadPath)
	torrentParams.SetSavePath(btp.bts.config.DownloadPath)

	btp.log.Infof("Checking for fast resume data in %s.fastresume", btp.infoHash)
	fastResumeFile := filepath.Join(btp.bts.config.TorrentsPath, fmt.Sprintf("%s.fastresume", btp.infoHash))
	if _, err := os.Stat(fastResumeFile); err == nil {
		btp.log.Info("Found fast resume data...")
		btp.fastResumeFile = fastResumeFile
		fastResumeData, err := ioutil.ReadFile(fastResumeFile)
		if err != nil {
			return err
		}
		fastResumeVector := libtorrent.NewStdVectorChar()
		for _, c := range fastResumeData {
			fastResumeVector.PushBack(c)
		}
		torrentParams.SetResumeData(fastResumeVector)
	}

	btp.torrentHandle = btp.bts.Session.AddTorrent(torrentParams)
	go btp.consumeAlerts()

	if btp.torrentHandle == nil {
		return fmt.Errorf("Unable to add torrent with URI %s", btp.uri)
	}

	btp.log.Info("Enabling sequential download")
	btp.torrentHandle.SetSequentialDownload(true)

	status := btp.torrentHandle.Status(uint(libtorrent.TorrentHandleQueryName))

	btp.torrentName = status.GetName()
	btp.log.Infof("Downloading %s", btp.torrentName)

	if status.GetHasMetadata() == true {
		btp.onMetadataReceived()
	}

	return nil
}
Example #22
0
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(QuasarLogo, "\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("Quasar", "LOCALIZE[30208]", config.AddonIcon())

	http.ListenAndServe(":"+strconv.Itoa(config.ListenPort), nil)
}
Example #23
0
func TraktMostCollectedMovies(ctx *gin.Context) {
	pageParam := ctx.DefaultQuery("page", "1")
	page, _ := strconv.Atoi(pageParam)
	movies, err := trakt.TopMovies("collected", pageParam)
	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
	}
	renderTraktMovies(movies, ctx, page)
}
Example #24
0
func TraktMostAnticipatedShows(ctx *gin.Context) {
	pageParam := ctx.DefaultQuery("page", "1")
	page, _ := strconv.Atoi(pageParam)
	shows, err := trakt.TopShows("anticipated", pageParam)
	if err != nil {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
	}
	renderTraktShows(shows, ctx, page)
}
Example #25
0
func AuthorizeTrakt(ctx *gin.Context) {
	err := trakt.Authorize(true)
	if err == nil {
		ctx.String(200, "")
	} else {
		xbmc.Notify("Quasar", err.Error(), config.AddonIcon())
		ctx.String(200, "")
	}
}
Example #26
0
func AddShow(ctx *gin.Context) {
	LibraryPath := config.Get().LibraryPath
	DBPath := filepath.Join(LibraryPath, fmt.Sprintf("%s.json", DBName))

	if fileInfo, err := os.Stat(LibraryPath); err != nil || fileInfo.IsDir() == false || LibraryPath == "" || LibraryPath == "." {
		xbmc.Notify("Quasar", "LOCALIZE[30220]", config.AddonIcon())
		ctx.String(404, "")
		return
	}

	showId := ctx.Params.ByName("showId")

	if inJsonDb, err := InJsonDB(showId, LShow); err != nil || inJsonDb == true {
		ctx.String(404, "")
		return
	}

	ShowsLibraryPath := filepath.Join(LibraryPath, "Shows")
	if _, err := os.Stat(ShowsLibraryPath); os.IsNotExist(err) {
		if err := os.Mkdir(ShowsLibraryPath, 0755); err != nil {
			libraryLog.Error("Unable to create library path for Shows")
			ctx.String(404, "")
			return
		}
	}

	if err := WriteShowStrm(showId, ShowsLibraryPath); err != nil {
		ctx.String(404, "")
		return
	}

	if err := UpdateJsonDB(DBPath, showId, LShow); err != nil {
		libraryLog.Error("Unable to update json DB")
		ctx.String(404, "")
		return
	}

	xbmc.Notify("Quasar", "LOCALIZE[30221]", config.AddonIcon())
	ctx.String(200, "")
	xbmc.VideoLibraryScan()
	ClearCache(ctx)
	xbmc.Refresh()
	libraryLog.Notice("Show added")
}
Example #27
0
func ShowEpisodeLinks(ctx *gin.Context) {
	seasonNumber, _ := strconv.Atoi(ctx.Params.ByName("season"))
	episodeNumber, _ := strconv.Atoi(ctx.Params.ByName("episode"))
	torrents, longName, err := showEpisodeLinks(ctx.Params.ByName("showId"), seasonNumber, episodeNumber)
	if err != nil {
		ctx.Error(err)
		return
	}

	if len(torrents) == 0 {
		xbmc.Notify("Quasar", "LOCALIZE[30205]", config.AddonIcon())
		return
	}

	choices := make([]string, 0, len(torrents))
	for _, torrent := range torrents {
		info := make([]string, 0)
		if torrent.Resolution > 0 {
			info = append(info, bittorrent.Resolutions[torrent.Resolution])
		}
		if torrent.Size != "" {
			info = append(info, fmt.Sprintf("[%s]", torrent.Size))
		}
		if torrent.RipType > 0 {
			info = append(info, bittorrent.Rips[torrent.RipType])
		}
		if torrent.VideoCodec > 0 {
			info = append(info, bittorrent.Codecs[torrent.VideoCodec])
		}
		if torrent.AudioCodec > 0 {
			info = append(info, bittorrent.Codecs[torrent.AudioCodec])
		}
		if torrent.Provider != "" {
			info = append(info, " - "+torrent.Provider)
		}

		torrentName := torrent.Name
		if len(torrentName) > 80 {
			torrentName = torrentName[:80]
		}

		label := fmt.Sprintf("[B](%d / %d) %s[/B]\n%s",
			torrent.Seeds,
			torrent.Peers,
			strings.Join(info, " "),
			torrentName,
		)
		choices = append(choices, label)
	}

	choice := xbmc.ListDialogLarge("LOCALIZE[30228]", longName, choices...)
	if choice >= 0 {
		rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[choice].Magnet())
		ctx.Redirect(302, rUrl)
	}
}
Example #28
0
func ListEntities(endpoint string, params napping.Params) []*Entity {
	var wg sync.WaitGroup
	entities := make([]*Entity, MaxPages*resultsPerPage)
	params["api_key"] = apiKey
	params["language"] = "en"

	wg.Add(MaxPages)
	for i := 0; i < MaxPages; i++ {
		go func(page int) {
			defer wg.Done()
			var tmp *EntityList
			tmpParams := napping.Params{
				"page": strconv.Itoa(startPage + page),
			}
			for k, v := range params {
				tmpParams[k] = v
			}
			urlValues := tmpParams.AsUrlValues()
			rateLimiter.Call(func() {
				resp, err := napping.Get(
					tmdbEndpoint+endpoint,
					&urlValues,
					&tmp,
					nil,
				)
				if err != nil {
					log.Error(err.Error())
					xbmc.Notify("Quasar", "ListEntities failed, check your logs.", config.AddonIcon())
				} else if resp.Status() != 200 {
					message := fmt.Sprintf("ListEntities bad status: %d", resp.Status())
					log.Error(message)
					xbmc.Notify("Quasar", message, config.AddonIcon())
				}
			})
			for i, entity := range tmp.Results {
				entities[page*resultsPerPage+i] = entity
			}
		}(i)
	}
	wg.Wait()

	return entities
}
Example #29
0
func MoviePlay(ctx *gin.Context) {
	torrents := movieLinks(ctx.Params.ByName("imdbId"))
	if len(torrents) == 0 {
		xbmc.Notify("Quasar", "LOCALIZE[30205]", config.AddonIcon())
		return
	}
	sort.Sort(sort.Reverse(providers.ByQuality(torrents)))
	rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[0].Magnet())
	ctx.Redirect(302, rUrl)
}
Example #30
0
func Scrobble(action string, contentType string, tmdbId int, runtime int) {
	if err := Authorized(); err != nil {
		return
	}
	if action != "update" {
		log.Notice(action, contentType, tmdbId)
	}

	retVal := xbmc.GetWatchTimes()

	errStr := retVal["error"]
	watchedTime, _ := strconv.ParseFloat(retVal["watchedTime"], 64)
	videoDuration, _ := strconv.ParseFloat(retVal["videoDuration"], 64)
	if errStr != "" {
		log.Warning(errStr)
	} else {
		scrobbleTime = watchedTime
		scrobbleEnd = videoDuration
	}
	if action == "update" {
		return
	}

	if scrobbleEnd == 0 {
		if runtime != 0 {
			scrobbleEnd = float64(runtime)
			log.Warningf("Using specified runtime of %d", runtime)
		} else {
			if contentType == "movie" {
				scrobbleEnd = 7200
			} else {
				scrobbleEnd = 2700
			}
			log.Warningf("Using fallback runtime of %d", videoDuration)
		}
	}

	progress := scrobbleTime / math.Floor(scrobbleEnd) * 100

	log.Infof("Progress: %f%%, watched: %fs, duration: %fs", progress, scrobbleTime, scrobbleEnd)

	if action == "stop" {
		scrobbleTime = 0
		scrobbleEnd = 0
	}

	endPoint := fmt.Sprintf("scrobble/%s", action)
	resp, err := Post(endPoint, bytes.NewBufferString(fmt.Sprintf(`{"%s": {"ids": {"tmdb": %d}}, "progress": %f}`, contentType, tmdbId, progress)))
	if err != nil {
		log.Error(err.Error())
		xbmc.Notify("Quasar", "Scrobble failed, check your logs.", config.AddonIcon())
	} else if resp.Status() != 201 {
		log.Errorf("Failed to scrobble %s #%d to %s at %f: %d", contentType, tmdbId, action, progress, resp.Status())
	}
}