2019-08-28 08:06:42 +00:00
|
|
|
package arn
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2019-11-28 01:00:08 +00:00
|
|
|
"time"
|
2019-08-28 08:06:42 +00:00
|
|
|
|
|
|
|
"github.com/aerogo/nano"
|
|
|
|
"github.com/animenotifier/notify.moe/arn/validate"
|
|
|
|
)
|
|
|
|
|
2019-11-18 05:01:13 +00:00
|
|
|
// EpisodeID represents an episode ID.
|
|
|
|
type EpisodeID = ID
|
|
|
|
|
2019-08-28 08:06:42 +00:00
|
|
|
// Episode represents a single episode for an anime.
|
|
|
|
type Episode struct {
|
|
|
|
AnimeID AnimeID `json:"animeId"`
|
|
|
|
Number int `json:"number" editable:"true"`
|
|
|
|
Title EpisodeTitle `json:"title" editable:"true"`
|
|
|
|
AiringDate AiringDate `json:"airingDate" editable:"true"`
|
|
|
|
Links map[string]string `json:"links"`
|
2019-11-18 05:01:13 +00:00
|
|
|
|
|
|
|
hasID
|
2019-08-28 08:06:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// EpisodeTitle contains the title information for an anime episode.
|
|
|
|
type EpisodeTitle struct {
|
|
|
|
Romaji string `json:"romaji" editable:"true"`
|
|
|
|
English string `json:"english" editable:"true"`
|
|
|
|
Japanese string `json:"japanese" editable:"true"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewAnimeEpisode creates a new anime episode.
|
|
|
|
func NewAnimeEpisode() *Episode {
|
|
|
|
return &Episode{
|
2019-11-18 05:01:13 +00:00
|
|
|
hasID: hasID{
|
|
|
|
ID: GenerateID("Episode"),
|
|
|
|
},
|
2019-08-28 08:06:42 +00:00
|
|
|
Number: -1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Anime returns the anime the episode refers to.
|
|
|
|
func (episode *Episode) Anime() *Anime {
|
|
|
|
anime, _ := GetAnime(episode.AnimeID)
|
|
|
|
return anime
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetID returns the episode ID.
|
|
|
|
func (episode *Episode) GetID() string {
|
|
|
|
return episode.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
// TypeName returns the type name.
|
|
|
|
func (episode *Episode) TypeName() string {
|
|
|
|
return "Episode"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Self returns the object itself.
|
|
|
|
func (episode *Episode) Self() Loggable {
|
|
|
|
return episode
|
|
|
|
}
|
|
|
|
|
|
|
|
// Link returns the permalink to the episode.
|
|
|
|
func (episode *Episode) Link() string {
|
|
|
|
return "/episode/" + episode.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
// Available tells you whether the episode is available (triggered when it has a link).
|
|
|
|
func (episode *Episode) Available() bool {
|
2019-11-28 01:00:08 +00:00
|
|
|
availableDate, err := time.Parse(time.RFC3339, episode.AiringDate.End)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
2019-08-28 08:06:42 +00:00
|
|
|
|
2019-11-28 01:00:08 +00:00
|
|
|
return time.Now().UnixNano() > availableDate.UnixNano()
|
2019-08-28 08:06:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Previous returns the previous episode, if available.
|
|
|
|
func (episode *Episode) Previous() *Episode {
|
|
|
|
episodes := episode.Anime().Episodes()
|
|
|
|
_, index := episodes.Find(episode.Number)
|
|
|
|
|
|
|
|
if index > 0 {
|
|
|
|
return episodes[index-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next returns the next episode, if available.
|
|
|
|
func (episode *Episode) Next() *Episode {
|
|
|
|
episodes := episode.Anime().Episodes()
|
|
|
|
_, index := episodes.Find(episode.Number)
|
|
|
|
|
|
|
|
if index != -1 && index+1 < len(episodes) {
|
|
|
|
return episodes[index+1]
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge combines the data of both episodes to one.
|
|
|
|
func (episode *Episode) Merge(b *Episode) {
|
|
|
|
if b == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
episode.Number = b.Number
|
|
|
|
|
|
|
|
// Titles
|
|
|
|
if b.Title.Romaji != "" {
|
|
|
|
episode.Title.Romaji = b.Title.Romaji
|
|
|
|
}
|
|
|
|
|
|
|
|
if b.Title.English != "" {
|
|
|
|
episode.Title.English = b.Title.English
|
|
|
|
}
|
|
|
|
|
|
|
|
if b.Title.Japanese != "" {
|
|
|
|
episode.Title.Japanese = b.Title.Japanese
|
|
|
|
}
|
|
|
|
|
|
|
|
// Airing date
|
|
|
|
if validate.DateTime(b.AiringDate.Start) {
|
|
|
|
episode.AiringDate.Start = b.AiringDate.Start
|
|
|
|
}
|
|
|
|
|
|
|
|
if validate.DateTime(b.AiringDate.End) {
|
|
|
|
episode.AiringDate.End = b.AiringDate.End
|
|
|
|
}
|
|
|
|
|
|
|
|
// Links
|
|
|
|
if episode.Links == nil {
|
|
|
|
episode.Links = map[string]string{}
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, link := range b.Links {
|
|
|
|
episode.Links[name] = link
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// String implements the default string serialization.
|
|
|
|
func (episode *Episode) String() string {
|
|
|
|
return fmt.Sprintf("%s ep. %d", episode.Anime().TitleByUser(nil), episode.Number)
|
|
|
|
}
|
|
|
|
|
|
|
|
// StreamEpisodes returns a stream of all episodes.
|
|
|
|
func StreamEpisodes() <-chan *Episode {
|
|
|
|
channel := make(chan *Episode, nano.ChannelBufferSize)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for obj := range DB.All("Episode") {
|
|
|
|
channel <- obj.(*Episode)
|
|
|
|
}
|
|
|
|
|
|
|
|
close(channel)
|
|
|
|
}()
|
|
|
|
|
|
|
|
return channel
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetEpisode returns the episode with the given ID.
|
2019-11-18 06:13:51 +00:00
|
|
|
func GetEpisode(id EpisodeID) (*Episode, error) {
|
2019-08-28 08:06:42 +00:00
|
|
|
obj, err := DB.Get("Episode", id)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj.(*Episode), nil
|
|
|
|
}
|