Example #1
0
func (a *addictedProxy) GetShowSubtitle(reqEpisode *polochon.ShowEpisode, log *logrus.Entry) (polochon.Subtitle, error) {
	// TODO: add year
	// TODO: handle release

	shows, err := a.client.GetTvShows()
	if err != nil {
		return nil, err
	}
	var guessID string
	guessDist := 1000
	for showName, showID := range shows {
		dist := levenshtein.Distance(strings.ToLower(showName), strings.ToLower(reqEpisode.ShowTitle))
		if dist < guessDist {
			guessDist = dist
			guessID = showID
		}
	}

	subtitles, err := a.client.GetSubtitles(guessID, reqEpisode.Season, reqEpisode.Episode)
	if err != nil {
		return nil, err
	}

	filteredSubs := subtitles.FilterByLang(a.language)
	if len(filteredSubs) == 0 {
		return nil, polochon.ErrNoSubtitleFound
	}

	sort.Sort(addicted.ByDownloads(filteredSubs))

	if reqEpisode.ReleaseGroup == "" {
		log.Info("No release group specified get the most downloaded subtitle")
		return &filteredSubs[0], err
	}

	subDist := 1000
	var subtitle polochon.Subtitle
	var release string

	for _, sub := range filteredSubs {
		dist := levenshtein.Distance(strings.ToLower(reqEpisode.ReleaseGroup), strings.ToLower(sub.Release))
		if dist < subDist {
			subDist = dist
			subtitle = &sub
			release = sub.Release
		}
	}
	log.Info("Subtitle chosen ", release, " whit distance ", subDist)
	return subtitle, err
}
Example #2
0
func main() {
	s1 := "kitten"
	s2 := "sitting"
	fmt.Printf("The distance between %v and %v is %v\n",
		s1, s2, levenshtein.Distance(s1, s2))
	// -> The distance between kitten and sitting is 3
}
Example #3
0
// getShowByName helps find a show on tvdb using its name
func getShowByName(s *polochon.Show) error {
	if s.Title == "" {
		return ErrMissingShowTitle
	}

	// Add the year to the search if defined
	query := s.Title
	if s.Year != 0 {
		query = fmt.Sprintf("%s (%d)", query, s.Year)
	}

	// Search on tvdb by name
	list, err := tvdbGetSeries(query)
	if err != nil {
		return err
	}

	// Any result ?
	if len(list.Series) == 0 {
		return ErrShowNotFound
	}

	// Find the most accurate serie base on the levenshtein distance
	var show *tvdb.Series
	minDistance := 100
	for _, tvdbSerie := range list.Series {
		d := levenshtein.Distance(query, tvdbSerie.SeriesName)
		if d < minDistance {
			minDistance = d
			show = tvdbSerie
		}
	}

	return updateShow(s, show)
}
Example #4
0
func calcScore(a, b string) float64 {
	score := levenshtein.Distance(a, b)
	lena := len(a)
	lenb := len(b)
	var bigger float64
	if lena > lenb {
		bigger = float64(lena)
	} else {
		bigger = float64(lenb)
	}
	return (bigger - float64(score)) / bigger
}
Example #5
0
// SearchByTitle searches a movie by its title. It adds the tmdb id into the
// movie struct so it can get details later
func (t *TmDB) searchByTitle(m *polochon.Movie, log *logrus.Entry) error {
	// No title, no search
	if m.Title == "" {
		return ErrNoMovieTitle
	}

	// ID already found
	if m.TmdbID != 0 {
		return nil
	}

	// Add year option if given
	options := map[string]string{}
	if m.Year != 0 {
		options["year"] = fmt.Sprintf("%d", m.Year)
	}

	// Search on tmdb
	r, err := tmdbSearchMovie(t.client, m.Title, options)
	if err != nil {
		return err
	}

	// Check if there is any results
	if len(r.Results) == 0 {
		log.Debugf("Failed to find movie from imdb title %q", m.Title)
		return ErrNoMovieFound
	}

	// Find the most accurate serie based on the levenshtein distance
	var movieShort tmdb.MovieShort
	minDistance := 100
	for _, result := range r.Results {
		d := levenshtein.Distance(m.Title, result.Title)
		if d < minDistance {
			minDistance = d
			movieShort = result
		}
	}

	m.TmdbID = movieShort.ID

	log.Debugf("Found movie from title %q", m.Title)

	return nil
}
Example #6
0
/**
 * Generate two random indices and a random number.
 * If the levenshtein distance between the names found at
 * index1 and index2 is the same as the random number,
 * one of index1 and index2 will be chosen at random to
 * be our winner.
 */
func raffle(names []string, winnerChannel chan string) {
	defer wg.Done()
	var index1, index2, n, d int
	var winner string
	for {
		index1 = rand.Int() % len(names)
		index2 = rand.Int() % len(names)
		n = 3 + rand.Int()%100
		d = levenshtein.Distance(names[index1], names[index2])
		if d == n {
			if rand.Int()%2 == 1 {
				winner = names[index1]
			} else {
				winner = names[index2]
			}
			winnerChannel <- winner
			return
		}
	}
}
Example #7
0
func getDistance(s1 string, s2 string) int {
	s1 = strings.ToLower(s1)
	s2 = strings.ToLower(s2)
	// dist := hamming.Calc(s1, s2)
	// if dist > 0 {
	// 	return dist
	// } else {
	dist := levenshtein.Distance(s1, s2)
	if Normalize {
		minWord := len(s1)
		if len(s2) < minWord {
			minWord = len(s2)
		}
		if dist > minWord {
			dist = (dist-minWord)/2 + minWord
		}
		lcsDist := LCS(s1, s2)
		dist = dist + -1*lcsDist
	}
	return dist
}
Example #8
0
// Guess helps find the best guess
func (g *Guesser) Guess() (*Guess, error) {
	// If nothing was found on imdb and guessit we're done
	if g.Guessit == nil && len(g.OpenSubtitle) == 0 {
		return nil, fmt.Errorf("openguessit: guessit and opensub failed to guess this file")
	}

	// If only guessit was found
	if len(g.OpenSubtitle) == 0 {
		return &Guess{Guessit: g.Guessit}, nil
	}

	// Rank the datas provided by OpenSubtitle and guessit
	guesses := []*Guess{}
	for _, sub := range g.OpenSubtitle {
		tmpGuess := &Guess{OpenSubtitle: sub}
		if g.Guessit != nil {
			if g.Guessit.Type == sub.Type {
				tmpGuess.Guessit = g.Guessit
				tmpGuess.Ranking += 10
			}
			// Movie
			if g.Guessit.Type == MovieType {
				d := levenshtein.Distance(sub.MovieName, g.Guessit.MovieName)
				// d == 0 means exact same name
				if d == 0 {
					d = 1
				}
				tmpGuess.Ranking += (1 / float64(d)) * 100
			}

			// Show
			if g.Guessit.Type == ShowType {
				if sub.Episode == g.Guessit.Episode && sub.Season == g.Guessit.Season {
					tmpGuess.Ranking += 100
				}

				d := levenshtein.Distance(sub.ShowName, g.Guessit.ShowName)
				if d == 0 {
					d = 1
				}
				tmpGuess.Ranking += (1 / float64(d)) * 100
			}

			// Year
			if sub.Year == g.Guessit.Year {
				tmpGuess.Ranking += 10
			}
		}

		// LevDist
		if sub.LevDist == 0 {
			sub.LevDist = 1
		}
		tmpGuess.Ranking += (1 / float64(sub.LevDist)) * 100

		guesses = append(guesses, tmpGuess)
	}

	var bestGuess *Guess
	for _, guess := range guesses {
		// First value
		if bestGuess == nil {
			bestGuess = guess
			continue
		}

		if guess.Ranking > bestGuess.Ranking {
			bestGuess = guess
		}
	}

	return bestGuess, nil
}
Example #9
0
// UpdateFromOpenSubtitle updates the guess with the OpenSubtitle informations
func (g *Guesser) UpdateFromOpenSubtitle() error {
	// Base path of the filename
	basePath := filepath.Base(g.FilePath)

	// OpenSubtitle client
	client, err := osdb.NewClient()
	if err != nil {
		return err
	}

	// Log in
	if err := client.LogIn("", "", "eng"); err != nil {
		return err
	}

	// Set the languages
	languages := []string{"eng"}

	// Hash movie file, and search
	subtitles, err := client.FileSearch(g.FilePath, languages)
	if err != nil {
		return err
	}

	// If nothing found, search by filename
	if len(subtitles) == 0 {
		client, err := osdb.NewClient()
		if err != nil {
			return err
		}

		err = client.LogIn("", "", "eng")
		if err != nil {
			return err
		}

		params := []interface{}{
			client.Token,
			[]map[string]string{
				{
					"query":         basePath,
					"sublanguageid": "en",
				},
			},
		}

		subtitles, err = client.SearchSubtitles(&params)
		if err != nil {
			return err
		}
	}

	// No subtitles found
	if len(subtitles) == 0 {
		return nil
	}

	for _, sub := range subtitles {
		switch sub.MovieKind {
		case MovieType:
			g.OpenSubtitle = append(g.OpenSubtitle, &OpenSubtitle{
				ImdbID:    fmt.Sprintf("tt%07s", sub.IDMovieImdb),
				Type:      MovieType,
				MovieName: sub.MovieFileName,
				Year:      sub.MovieYear,
				LevDist:   levenshtein.Distance(sub.SubFileName, basePath),
			})
		case ShowType:
			// The MovieFileName field returned by openSubtitles contains the
			// show name and the episode name.
			// e.g. `"Show Title" Show episode title`
			// Only the title is relevant
			showName := sub.MovieFileName
			s := strings.Split(sub.MovieFileName, `"`)
			if len(s) >= 2 {
				showName = s[1]
			}

			g.OpenSubtitle = append(g.OpenSubtitle, &OpenSubtitle{
				ImdbID:   fmt.Sprintf("tt%07s", sub.SeriesIMDBParent),
				Type:     ShowType,
				ShowName: showName,
				Season:   sub.SeriesSeason,
				Episode:  sub.SeriesEpisode,
				Year:     sub.MovieYear,
				LevDist:  levenshtein.Distance(sub.SubFileName, basePath),
			})
		default:
			return fmt.Errorf("Invalid movie kind: %q", sub.MovieKind)
		}
	}

	return nil
}