Episodes and movies stuff #18
@ -1,6 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
@ -30,41 +31,31 @@ const (
|
|||||||
|
|
||||||
// episodeDB represents the Episode in the DB
|
// episodeDB represents the Episode in the DB
|
||||||
type episodeDB struct {
|
type episodeDB struct {
|
||||||
ID string `db:"id"`
|
ID string `db:"id"`
|
||||||
TvdbID int `db:"tvdb_id"`
|
TvdbID int `db:"tvdb_id"`
|
||||||
ImdbID string `db:"imdb_id"`
|
ImdbID string `db:"imdb_id"`
|
||||||
ShowImdbID string `db:"show_imdb_id"`
|
ShowImdbID string `db:"show_imdb_id"`
|
||||||
ShowTvdbID int `db:"show_tvdb_id"`
|
ShowTvdbID int `db:"show_tvdb_id"`
|
||||||
Season int `db:"season"`
|
Season int `db:"season"`
|
||||||
Episode int `db:"episode"`
|
Episode int `db:"episode"`
|
||||||
Title string `db:"title"`
|
Title string `db:"title"`
|
||||||
Rating float32 `db:"rating"`
|
Rating float32 `db:"rating"`
|
||||||
Plot string `db:"plot"`
|
Plot string `db:"plot"`
|
||||||
Thumb string `db:"thumb"`
|
Thumb string `db:"thumb"`
|
||||||
Runtime int `db:"runtime"`
|
Runtime int `db:"runtime"`
|
||||||
Aired string `db:"aired"`
|
Aired string `db:"aired"`
|
||||||
ReleaseGroup string `db:"release_group"`
|
Created time.Time `db:"created_at"`
|
||||||
Created time.Time `db:"created_at"`
|
Updated time.Time `db:"updated_at"`
|
||||||
Updated time.Time `db:"updated_at"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEpisodeFromPolochon returns an episodeDB from a polochon ShowEpisode
|
// getEpisodeDB returns an episodeDB from a polochon.ShowEpisode
|
||||||
func NewEpisodeFromPolochon(e *polochon.ShowEpisode) *episodeDB {
|
func getEpisodeDB(db *sqlx.DB, episode *polochon.ShowEpisode) (*episodeDB, error) {
|
||||||
return &episodeDB{
|
var episodeDB episodeDB
|
||||||
TvdbID: e.TvdbID,
|
err := db.QueryRowx(getEpisodeQuery, episode.ShowImdbID, episode.Season, episode.Episode).StructScan(&episodeDB)
|
||||||
ImdbID: e.EpisodeImdbID,
|
if err != nil {
|
||||||
ShowImdbID: e.ShowImdbID,
|
return &episodeDB, err
|
||||||
ShowTvdbID: e.ShowTvdbID,
|
|
||||||
Season: e.Season,
|
|
||||||
Episode: e.Episode,
|
|
||||||
Title: e.Title,
|
|
||||||
Rating: e.Rating,
|
|
||||||
Plot: e.Plot,
|
|
||||||
Thumb: e.Thumb,
|
|
||||||
Runtime: e.Runtime,
|
|
||||||
Aired: e.Aired,
|
|
||||||
ReleaseGroup: e.ReleaseGroup,
|
|
||||||
}
|
}
|
||||||
|
return &episodeDB, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEpisodeFromDB returns a new polochon ShowEpisode from an episodeDB
|
// NewEpisodeFromDB returns a new polochon ShowEpisode from an episodeDB
|
||||||
@ -76,10 +67,19 @@ func NewEpisodeFromDB(eDB *episodeDB) *polochon.ShowEpisode {
|
|||||||
|
|
||||||
// FillEpisodeFromDB fills a ShowEpisode from an episodeDB
|
// FillEpisodeFromDB fills a ShowEpisode from an episodeDB
|
||||||
func FillEpisodeFromDB(eDB *episodeDB, pEpisode *polochon.ShowEpisode) {
|
func FillEpisodeFromDB(eDB *episodeDB, pEpisode *polochon.ShowEpisode) {
|
||||||
pEpisode.TvdbID = eDB.TvdbID
|
// Keep the data that never changes but only if we have it
|
||||||
pEpisode.EpisodeImdbID = eDB.ImdbID
|
if eDB.TvdbID != 0 {
|
||||||
pEpisode.ShowImdbID = eDB.ShowImdbID
|
pEpisode.TvdbID = eDB.TvdbID
|
||||||
pEpisode.ShowTvdbID = eDB.ShowTvdbID
|
}
|
||||||
|
if eDB.ImdbID != "" {
|
||||||
|
pEpisode.EpisodeImdbID = eDB.ImdbID
|
||||||
|
}
|
||||||
|
if eDB.ShowImdbID != "" {
|
||||||
|
pEpisode.ShowImdbID = eDB.ShowImdbID
|
||||||
|
}
|
||||||
|
if eDB.ShowTvdbID != 0 {
|
||||||
|
pEpisode.ShowTvdbID = eDB.ShowTvdbID
|
||||||
|
}
|
||||||
pEpisode.Season = eDB.Season
|
pEpisode.Season = eDB.Season
|
||||||
pEpisode.Episode = eDB.Episode
|
pEpisode.Episode = eDB.Episode
|
||||||
pEpisode.Title = eDB.Title
|
pEpisode.Title = eDB.Title
|
||||||
@ -92,13 +92,12 @@ func FillEpisodeFromDB(eDB *episodeDB, pEpisode *polochon.ShowEpisode) {
|
|||||||
|
|
||||||
// GetEpisode gets an episode and fills the polochon episode
|
// GetEpisode gets an episode and fills the polochon episode
|
||||||
func GetEpisode(db *sqlx.DB, pEpisode *polochon.ShowEpisode) error {
|
func GetEpisode(db *sqlx.DB, pEpisode *polochon.ShowEpisode) error {
|
||||||
var episodeDB episodeDB
|
episodeDB, err := getEpisodeDB(db, pEpisode)
|
||||||
err := db.QueryRowx(getEpisodeQuery, pEpisode.ShowImdbID, pEpisode.Season, pEpisode.Episode).StructScan(&episodeDB)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
FillEpisodeFromDB(&episodeDB, pEpisode)
|
FillEpisodeFromDB(episodeDB, pEpisode)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -125,13 +124,65 @@ func GetEpisodes(db *sqlx.DB, pShow *polochon.Show, log *logrus.Entry) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateFromEpisode will update the episodeDB from a ShowEpisode
|
||||||
|
// We just make sure to never update the episodeDB with empty value
|
||||||
|
func (e *episodeDB) updateFromEpisode(showEpisode *polochon.ShowEpisode) {
|
||||||
|
if showEpisode.TvdbID != 0 {
|
||||||
|
e.TvdbID = showEpisode.TvdbID
|
||||||
|
}
|
||||||
|
if showEpisode.EpisodeImdbID != "" {
|
||||||
|
e.ImdbID = showEpisode.EpisodeImdbID
|
||||||
|
}
|
||||||
|
if showEpisode.ShowImdbID != "" {
|
||||||
|
e.ShowImdbID = showEpisode.ShowImdbID
|
||||||
|
}
|
||||||
|
if showEpisode.ShowTvdbID != 0 {
|
||||||
|
e.ShowTvdbID = showEpisode.ShowTvdbID
|
||||||
|
}
|
||||||
|
if showEpisode.Season != 0 {
|
||||||
|
e.Season = showEpisode.Season
|
||||||
|
}
|
||||||
|
if showEpisode.Episode != 0 {
|
||||||
|
e.Episode = showEpisode.Episode
|
||||||
|
}
|
||||||
|
if showEpisode.Title != "" {
|
||||||
|
e.Title = showEpisode.Title
|
||||||
|
}
|
||||||
|
if showEpisode.Rating != 0 {
|
||||||
|
e.Rating = showEpisode.Rating
|
||||||
|
}
|
||||||
|
if showEpisode.Plot != "" {
|
||||||
|
e.Plot = showEpisode.Plot
|
||||||
|
}
|
||||||
|
if showEpisode.Thumb != "" {
|
||||||
|
e.Thumb = showEpisode.Thumb
|
||||||
|
}
|
||||||
|
if showEpisode.Runtime != 0 {
|
||||||
|
e.Runtime = showEpisode.Runtime
|
||||||
|
}
|
||||||
|
if showEpisode.Aired != "" {
|
||||||
|
e.Aired = showEpisode.Aired
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UpsertEpisode upserts the episode
|
// UpsertEpisode upserts the episode
|
||||||
func UpsertEpisode(db *sqlx.DB, showEpisode *polochon.ShowEpisode) error {
|
func UpsertEpisode(db *sqlx.DB, showEpisode *polochon.ShowEpisode) error {
|
||||||
e := NewEpisodeFromPolochon(showEpisode)
|
// Try to get the episode
|
||||||
r, err := db.NamedQuery(upsertEpisodeQuery, e)
|
episodeDB, err := getEpisodeDB(db, showEpisode)
|
||||||
|
// Return only if the error is != sql.ErrNoRows
|
||||||
|
if err != nil {
|
||||||
|
if err != sql.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the episodeDB from the showEpisode we have
|
||||||
|
episodeDB.updateFromEpisode(showEpisode)
|
||||||
|
r, err := db.NamedQuery(upsertEpisodeQuery, episodeDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -34,7 +35,6 @@ type movieDB struct {
|
|||||||
ID string `db:"id"`
|
ID string `db:"id"`
|
||||||
ImdbID string `db:"imdb_id"`
|
ImdbID string `db:"imdb_id"`
|
||||||
TmdbID int `db:"tmdb_id"`
|
TmdbID int `db:"tmdb_id"`
|
||||||
UserID *string `db:"user_id"`
|
|
||||||
Title string `db:"title"`
|
Title string `db:"title"`
|
||||||
OriginalTitle string `db:"original_title"`
|
OriginalTitle string `db:"original_title"`
|
||||||
SortTitle string `db:"sort_title"`
|
SortTitle string `db:"sort_title"`
|
||||||
@ -49,27 +49,34 @@ type movieDB struct {
|
|||||||
Updated time.Time `db:"updated_at"`
|
Updated time.Time `db:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMovieDB(db *sqlx.DB, movie *polochon.Movie) (*movieDB, error) {
|
||||||
|
var mDB movieDB
|
||||||
|
err := db.QueryRowx(getMovieQueryByImdbID, movie.ImdbID).StructScan(&mDB)
|
||||||
|
if err != nil {
|
||||||
|
return &mDB, err
|
||||||
|
}
|
||||||
|
return &mDB, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetMovie fills show details of a polochon.Movie
|
// GetMovie fills show details of a polochon.Movie
|
||||||
func GetMovie(db *sqlx.DB, pMovie *polochon.Movie) error {
|
func GetMovie(db *sqlx.DB, pMovie *polochon.Movie) error {
|
||||||
var mDB movieDB
|
if pMovie.ImdbID == "" {
|
||||||
var err error
|
return fmt.Errorf("Can't get movie details, you have to specify an ImdbID")
|
||||||
if pMovie.ImdbID != "" {
|
|
||||||
// Get the data from the DB
|
|
||||||
err = db.QueryRowx(getMovieQueryByImdbID, pMovie.ImdbID).StructScan(&mDB)
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("Can't get movie details, you have to specify an ImdbID")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the movie from the DB
|
||||||
|
movie, err := getMovieDB(db, pMovie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fills the polochon.Movie from the movieDB
|
// Fills the polochon.Movie from the movieDB
|
||||||
FillFromDB(&mDB, pMovie)
|
FillMovieFromDB(movie, pMovie)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FillFromDB fills a Movie from a movieDB extracted from the DB
|
// FillMovieFromDB fills a Movie from a movieDB extracted from the DB
|
||||||
func FillFromDB(mDB *movieDB, pMovie *polochon.Movie) {
|
func FillMovieFromDB(mDB *movieDB, pMovie *polochon.Movie) {
|
||||||
pMovie.ImdbID = mDB.ImdbID
|
pMovie.ImdbID = mDB.ImdbID
|
||||||
pMovie.Title = mDB.Title
|
pMovie.Title = mDB.Title
|
||||||
pMovie.Rating = mDB.Rating
|
pMovie.Rating = mDB.Rating
|
||||||
@ -84,10 +91,61 @@ func FillFromDB(mDB *movieDB, pMovie *polochon.Movie) {
|
|||||||
pMovie.Tagline = mDB.Tagline
|
pMovie.Tagline = mDB.Tagline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateFromMovie will update the movieDB from a Movie
|
||||||
|
// We just make sure to never update the movieDB with empty value
|
||||||
|
func (m *movieDB) updateFromMovie(movie *polochon.Movie) {
|
||||||
|
if movie.ImdbID != "" {
|
||||||
|
m.ImdbID = movie.ImdbID
|
||||||
|
}
|
||||||
|
if movie.TmdbID != 0 {
|
||||||
|
m.TmdbID = movie.TmdbID
|
||||||
|
}
|
||||||
|
if movie.Title != "" {
|
||||||
|
m.Title = movie.Title
|
||||||
|
}
|
||||||
|
if movie.OriginalTitle != "" {
|
||||||
|
m.OriginalTitle = movie.OriginalTitle
|
||||||
|
}
|
||||||
|
if movie.SortTitle != "" {
|
||||||
|
m.SortTitle = movie.SortTitle
|
||||||
|
}
|
||||||
|
if movie.Rating != 0 {
|
||||||
|
m.Rating = movie.Rating
|
||||||
|
}
|
||||||
|
if movie.Votes != 0 {
|
||||||
|
m.Votes = movie.Votes
|
||||||
|
}
|
||||||
|
if movie.Plot != "" {
|
||||||
|
m.Plot = movie.Plot
|
||||||
|
}
|
||||||
|
if movie.Year != 0 {
|
||||||
|
m.Year = movie.Year
|
||||||
|
}
|
||||||
|
if movie.Runtime != 0 {
|
||||||
|
m.Runtime = movie.Runtime
|
||||||
|
}
|
||||||
|
if movie.Tagline != "" {
|
||||||
|
m.Tagline = movie.Tagline
|
||||||
|
}
|
||||||
|
if movie.Genres != nil {
|
||||||
|
m.Genres = movie.Genres
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UpsertMovie upsert a polochon Movie in the database
|
// UpsertMovie upsert a polochon Movie in the database
|
||||||
func UpsertMovie(db *sqlx.DB, pMovie *polochon.Movie) error {
|
func UpsertMovie(db *sqlx.DB, pMovie *polochon.Movie) error {
|
||||||
mDB := NewMovieDB(pMovie)
|
// Try to get the movie
|
||||||
r, err := db.NamedQuery(upsertMovieQuery, mDB)
|
movieDB, err := getMovieDB(db, pMovie)
|
||||||
|
// Return only if the error is != sql.ErrNoRows
|
||||||
|
if err != nil {
|
||||||
|
if err != sql.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the movieDB from the movie we have
|
||||||
|
movieDB.updateFromMovie(pMovie)
|
||||||
|
r, err := db.NamedQuery(upsertMovieQuery, movieDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -96,9 +154,9 @@ func UpsertMovie(db *sqlx.DB, pMovie *polochon.Movie) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMovieDB returns a Movie ready to be put in DB from a
|
// newMovieDB returns a Movie ready to be put in DB from a
|
||||||
// polochon Movie
|
// polochon Movie
|
||||||
func NewMovieDB(m *polochon.Movie) movieDB {
|
func newMovieDB(m *polochon.Movie) movieDB {
|
||||||
genres := []string{}
|
genres := []string{}
|
||||||
if m.Genres != nil {
|
if m.Genres != nil {
|
||||||
genres = m.Genres
|
genres = m.Genres
|
||||||
|
2
go.mod
2
go.mod
@ -16,7 +16,7 @@ require (
|
|||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||||
github.com/odwrtw/errors v0.0.0-20170604160533-c747b9d17833
|
github.com/odwrtw/errors v0.0.0-20170604160533-c747b9d17833
|
||||||
github.com/odwrtw/papi v0.0.0-20190511132159-936937ad8b6a
|
github.com/odwrtw/papi v0.0.0-20190511132159-936937ad8b6a
|
||||||
github.com/odwrtw/polochon v0.0.0-20200403121328-985a643dc6aa
|
github.com/odwrtw/polochon v0.0.0-20200404170220-273fe65c963b
|
||||||
github.com/phyber/negroni-gzip v0.0.0-20180113114010-ef6356a5d029
|
github.com/phyber/negroni-gzip v0.0.0-20180113114010-ef6356a5d029
|
||||||
github.com/pioz/tvdb v0.0.0-20190503215423-f45c687faba9 // indirect
|
github.com/pioz/tvdb v0.0.0-20190503215423-f45c687faba9 // indirect
|
||||||
github.com/robfig/cron v1.1.0
|
github.com/robfig/cron v1.1.0
|
||||||
|
8
go.sum
8
go.sum
@ -137,12 +137,12 @@ github.com/odwrtw/papi v0.0.0-20190413103029-bd5bfea85ae6 h1:bF8XKFfYNY4quRdqJ5E
|
|||||||
github.com/odwrtw/papi v0.0.0-20190413103029-bd5bfea85ae6/go.mod h1:CXotdtODLpW0/yuFV5XH8Rmrj0eAfPLvdMKykPM2WCk=
|
github.com/odwrtw/papi v0.0.0-20190413103029-bd5bfea85ae6/go.mod h1:CXotdtODLpW0/yuFV5XH8Rmrj0eAfPLvdMKykPM2WCk=
|
||||||
github.com/odwrtw/papi v0.0.0-20190511132159-936937ad8b6a h1:9mdPet/ianrckPWR2jSekoafz6BaqbF7kPXLnDEIKu8=
|
github.com/odwrtw/papi v0.0.0-20190511132159-936937ad8b6a h1:9mdPet/ianrckPWR2jSekoafz6BaqbF7kPXLnDEIKu8=
|
||||||
github.com/odwrtw/papi v0.0.0-20190511132159-936937ad8b6a/go.mod h1:eY0skvVHJBwbSJ18uq2c1T4SvhdEV8R0XFSb0zKh5Yo=
|
github.com/odwrtw/papi v0.0.0-20190511132159-936937ad8b6a/go.mod h1:eY0skvVHJBwbSJ18uq2c1T4SvhdEV8R0XFSb0zKh5Yo=
|
||||||
github.com/odwrtw/polochon v0.0.0-20200403121328-985a643dc6aa h1:Jh5cSZCcBwzULN9po+0mzydbPqiMRZAXkScON7BNvVw=
|
github.com/odwrtw/polochon v0.0.0-20200404170220-273fe65c963b h1:XBJs10QfMcVOr+jMpB2k8Pwfe4ohIWNMfNGStJdi1Pg=
|
||||||
github.com/odwrtw/polochon v0.0.0-20200403121328-985a643dc6aa/go.mod h1:vb6PuVZ0ToGnfgVxijvUdYsayoItmdOYSVM8yMnEtJo=
|
github.com/odwrtw/polochon v0.0.0-20200404170220-273fe65c963b/go.mod h1:6/D6IYxfGqRi8KioWN8ViiwssUdjhZV+U7gw5Xb8Aqk=
|
||||||
github.com/odwrtw/tpb v0.0.0-20200130133144-c846aa382c6f h1:fwEIGT+o3e8+XkBqrwsE3/+9ketTQXflPhCkv3/w990=
|
github.com/odwrtw/tpb v0.0.0-20200130133144-c846aa382c6f h1:fwEIGT+o3e8+XkBqrwsE3/+9ketTQXflPhCkv3/w990=
|
||||||
github.com/odwrtw/tpb v0.0.0-20200130133144-c846aa382c6f/go.mod h1:updLvMbQo2xHoz94MX9+GqmSoKhf6E8fs/J+wLvvu6A=
|
github.com/odwrtw/tpb v0.0.0-20200130133144-c846aa382c6f/go.mod h1:updLvMbQo2xHoz94MX9+GqmSoKhf6E8fs/J+wLvvu6A=
|
||||||
github.com/odwrtw/trakttv v0.0.0-20170418094324-76889e438555 h1:5JfY2cKMq0g+IpgAaY+6EPRZZK8eV2lgRIUsqPB+hBY=
|
github.com/odwrtw/trakttv v0.0.0-20200404161731-0d594827e4f9 h1:PuQLHO75MXUsJpf9BcTVxvR/FCkdn1MZnZt6h3o6cJI=
|
||||||
github.com/odwrtw/trakttv v0.0.0-20170418094324-76889e438555/go.mod h1:vb2u+kCVrf+HyvVMzmTzisu+OUsBwwGfFtEmT+S5nzw=
|
github.com/odwrtw/trakttv v0.0.0-20200404161731-0d594827e4f9/go.mod h1:I2ogRfOYYqNpMhljPYdFUVUrLbZQ89Ba7QdfiW6EcJ0=
|
||||||
github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 h1:NZz8yuBWWG4o3EGdoMap4o+JPKLBhqeSQ7nTfX6XPos=
|
github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 h1:NZz8yuBWWG4o3EGdoMap4o+JPKLBhqeSQ7nTfX6XPos=
|
||||||
github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7/go.mod h1:geyfqmhRrxMwbEo5RPwf5rw5vITQHHQlA7+azUQSIJM=
|
github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7/go.mod h1:geyfqmhRrxMwbEo5RPwf5rw5vITQHHQlA7+azUQSIJM=
|
||||||
github.com/odwrtw/yifysubs v0.0.0-20190417174645-d3bba6e4cfe0 h1:LasNCTYd9Pc3x34xc1p054ZF8rVPLhD2Vfk3Db2KSpo=
|
github.com/odwrtw/yifysubs v0.0.0-20190417174645-d3bba6e4cfe0 h1:LasNCTYd9Pc3x34xc1p054ZF8rVPLhD2Vfk3Db2KSpo=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user