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) }
func Lookup(ctx *gin.Context) { var db DataBase LibraryPath := config.Get().LibraryPath DBPath := filepath.Join(LibraryPath, fmt.Sprintf("%s.json", DBName)) if _, err := os.Stat(DBPath); err == nil { file, err := ioutil.ReadFile(DBPath) if err != nil { ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") ctx.JSON(200, gin.H{ "success": false, }) return } json.Unmarshal(file, &db) } Movies := make([]*Item, 0, len(db.Movies)) Shows := make([]*Item, 0, len(db.Shows)) for i := 0; i < len(db.Movies); i++ { movie := tmdb.GetMovieById(db.Movies[i], "en") Movies = append(Movies, &Item{ Id: db.Movies[i], Title: movie.OriginalTitle, Year: strings.Split(movie.ReleaseDate, "-")[0], Overview: movie.Overview, Poster: tmdb.ImageURL(movie.PosterPath, "w500"), }) } for i := 0; i < len(db.Shows); i++ { showId, _ := strconv.Atoi(db.Shows[i]) show := tmdb.GetShow(showId, "en") if show == nil { ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") ctx.JSON(200, gin.H{ "success": false, }) return } Shows = append(Shows, &Item{ Id: db.Shows[i], Title: show.Name, Year: strings.Split(show.FirstAirDate, "-")[0], Overview: show.Overview, Poster: tmdb.ImageURL(show.PosterPath, "w500"), }) } ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") ctx.JSON(200, gin.H{ "success": true, "results": gin.H{ "movies": Movies, "shows": Shows, }, }) }
func ShowEpisodes(ctx *gin.Context) { showId, _ := strconv.Atoi(ctx.Params.ByName("showId")) seasonNumber, _ := strconv.Atoi(ctx.Params.ByName("season")) language := config.Get().Language show := tmdb.GetShow(showId, language) season := tmdb.GetSeason(showId, seasonNumber, language) items := season.Episodes.ToListItems(show, season) for _, item := range items { playUrl := UrlForXBMC("/show/%d/season/%d/episode/%d/play", show.Id, seasonNumber, item.Info.Episode, ) episodeLinksUrl := UrlForXBMC("/show/%d/season/%d/episode/%d/links", show.Id, seasonNumber, item.Info.Episode, ) if config.Get().ChooseStreamAuto == true { item.Path = playUrl } else { item.Path = episodeLinksUrl } item.ContextMenu = [][]string{ []string{"LOCALIZE[30202]", fmt.Sprintf("XBMC.PlayMedia(%s)", episodeLinksUrl)}, []string{"LOCALIZE[30023]", fmt.Sprintf("XBMC.PlayMedia(%s)", playUrl)}, []string{"LOCALIZE[30203]", "XBMC.Action(Info)"}, []string{"LOCALIZE[30037]", fmt.Sprintf("XBMC.RunPlugin(%s)", UrlForXBMC("/setviewmode/episodes"))}, } item.IsPlayable = true } ctx.JSON(200, xbmc.NewView("episodes", items)) }
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") }
func ProviderGetEpisode(ctx *gin.Context) { provider := ctx.Params.ByName("provider") showId, _ := strconv.Atoi(ctx.Params.ByName("showId")) seasonNumber, _ := strconv.Atoi(ctx.Params.ByName("season")) episodeNumber, _ := strconv.Atoi(ctx.Params.ByName("episode")) log.Println("Searching links for TMDB Id:", showId) show := tmdb.GetShow(showId, "en") season := tmdb.GetSeason(showId, seasonNumber, "en") if season == nil { ctx.Error(errors.New(fmt.Sprintf("Unable to get season %d", seasonNumber))) return } episode := season.Episodes[episodeNumber-1] log.Printf("Resolved %s to %s", showId, show.Name) searcher := providers.NewAddonSearcher(provider) torrents := searcher.SearchEpisodeLinks(show, episode) if ctx.Request.URL.Query().Get("resolve") == "true" { for _, torrent := range torrents { torrent.Resolve() } } data, err := json.MarshalIndent(providerDebugResponse{ Payload: searcher.GetEpisodeSearchObject(show, episode), Results: torrents, }, "", " ") if err != nil { xbmc.AddonFailure(provider) ctx.Error(err) } ctx.Data(200, "application/json", data) }
func WriteShowStrm(showId string, ShowsLibraryPath string) error { Id, _ := strconv.Atoi(showId) show := tmdb.GetShow(Id, "en") if show == nil { return errors.New("Unable to get Show") } ShowStrm := toFileName(fmt.Sprintf("%s (%s)", show.Name, strings.Split(show.FirstAirDate, "-")[0])) ShowPath := filepath.Join(ShowsLibraryPath, ShowStrm) if _, err := os.Stat(ShowPath); os.IsNotExist(err) { if err := os.Mkdir(ShowPath, 0755); err != nil { libraryLog.Error("Unable to create path for Show") return err } } now := time.Now().UTC() addSpecials := config.Get().AddSpecials for _, season := range show.Seasons { if season.EpisodeCount == 0 { continue } firstAired, _ := time.Parse("2006-01-02", show.FirstAirDate) if firstAired.After(now) { continue } if addSpecials == false && season.Season == 0 { continue } episodes := tmdb.GetSeason(Id, season.Season, "en").Episodes for _, episode := range episodes { if episode.AirDate == "" { continue } firstAired, _ := time.Parse("2006-01-02", episode.AirDate) if firstAired.After(now) { continue } EpisodeStrmPath := filepath.Join(ShowPath, fmt.Sprintf("%s S%02dE%02d.strm", ShowStrm, season.Season, episode.EpisodeNumber)) playLink := UrlForXBMC("/library/play/show/%d/season/%d/episode/%d", Id, season.Season, episode.EpisodeNumber) if err := ioutil.WriteFile(EpisodeStrmPath, []byte(playLink), 0644); err != nil { libraryLog.Error("Unable to write to strm file for episode") return err } } } return nil }
func (as *AddonSearcher) GetEpisodeSearchObject(show *tvdb.Show, episode *tvdb.Episode) *EpisodeSearchObject { seriesName := show.SeriesName absoluteNumber := 0 tmdbFindResults := tmdb.Find(strconv.Itoa(show.Id), "tvdb_id") // FIXME: This can crash if tmdbFindResults != nil { var tmdbShow *tmdb.Show for _, result := range tmdbFindResults.TVResults { tmdbShow = tmdb.GetShow(result.Id, "en") break } if tmdbShow != nil { seriesName = tmdbShow.Name } // is this an anime? countryIsJP := false for _, country := range tmdbShow.OriginCountry { if country == "JP" { countryIsJP = true break } } genreIsAnim := false for _, genre := range tmdbShow.Genres { if genre.Name == "Animation" { genreIsAnim = true break } } if countryIsJP && genreIsAnim { absoluteNumber = episode.AbsoluteNumber } } return &EpisodeSearchObject{ IMDBId: show.ImdbId, TVDBId: show.Id, Title: NormalizeTitle(seriesName), Season: episode.SeasonNumber, Episode: episode.EpisodeNumber, AbsoluteNumber: absoluteNumber, } }
func ShowSeasons(ctx *gin.Context) { showId, _ := strconv.Atoi(ctx.Params.ByName("showId")) show := tmdb.GetShow(showId, config.Get().Language) items := show.Seasons.ToListItems(show) reversedItems := make(xbmc.ListItems, 0) for i := len(items) - 1; i >= 0; i-- { item := items[i] item.Path = UrlForXBMC("/show/%d/season/%d/episodes", show.Id, item.Info.Season) item.ContextMenu = [][]string{ []string{"LOCALIZE[30036]", fmt.Sprintf("XBMC.RunPlugin(%s)", UrlForXBMC("/setviewmode/seasons"))}, } reversedItems = append(reversedItems, item) } // xbmc.ListItems always returns false to Less() so that order is unchanged ctx.JSON(200, xbmc.NewView("seasons", reversedItems)) }
func showSeasonLinks(showId int, seasonNumber int) ([]*bittorrent.Torrent, error) { log.Println("Searching links for TMDB Id:", showId) show := tmdb.GetShow(showId, config.Get().Language) season := tmdb.GetSeason(showId, seasonNumber, config.Get().Language) if season == nil { return nil, errors.New("Unable to find season") } log.Printf("Resolved %d to %s", showId, show.Name) if torrents := InTorrentsMap(strconv.Itoa(season.Id)); len(torrents) > 0 { return torrents, nil } searchers := providers.GetSeasonSearchers() if len(searchers) == 0 { xbmc.Notify("Quasar", "LOCALIZE[30204]", config.AddonIcon()) } return providers.SearchSeason(searchers, show, season), nil }
func showEpisodeLinks(showId int, seasonNumber int, episodeNumber int) ([]*bittorrent.Torrent, string, error) { log.Println("Searching links for TMDB Id:", showId) show := tmdb.GetShow(showId, config.Get().Language) season := tmdb.GetSeason(showId, seasonNumber, config.Get().Language) if season == nil { return nil, "", errors.New("Unable to find season") } episode := season.Episodes[episodeNumber-1] log.Printf("Resolved %d to %s", showId, show.Name) searchers := providers.GetEpisodeSearchers() if len(searchers) == 0 { xbmc.Notify("Quasar", "LOCALIZE[30204]", config.AddonIcon()) } longName := fmt.Sprintf("%s S%02dE%02d", show.Name, seasonNumber, episodeNumber) return providers.SearchEpisode(searchers, show, episode), longName, nil }
func ShowEpisodeLinks(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, "") longName := fmt.Sprintf("%s S%02dE%02d", show.Name, 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 } choices := make([]string, 0, len(torrents)) for _, torrent := range torrents { resolution := "" if torrent.Resolution > 0 { resolution = fmt.Sprintf("[B][COLOR %s]%s[/COLOR][/B] ", bittorrent.Colors[torrent.Resolution], bittorrent.Resolutions[torrent.Resolution]) } info := make([]string, 0) if torrent.Size != "" { info = append(info, fmt.Sprintf("[B][%s][/B]", 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, fmt.Sprintf(" - [B]%s[/B]", torrent.Provider)) } multi := "" if torrent.Multi { multi = "\nmulti" } label := fmt.Sprintf("%s(%d / %d) %s\n%s\n%s%s", resolution, torrent.Seeds, torrent.Peers, strings.Join(info, " "), torrent.Name, torrent.Icon, multi, ) choices = append(choices, label) } choice := xbmc.ListDialogLarge("LOCALIZE[30228]", longName, choices...) if choice >= 0 { AddToTorrentsMap(strconv.Itoa(episode.Id), torrents[choice]) rUrl := UrlQuery( UrlForXBMC("/play"), "uri", torrents[choice].Magnet(), "tmdb", strconv.Itoa(episode.Id), "type", "episode", "runtime", strconv.Itoa(runtime)) ctx.Redirect(302, rUrl) } }