func ExampleEpisodeList_Add() { a := misc.ParseEpisodeList("1-3") a.Add(misc.ParseEpisode("3.1")) fmt.Println(a) a.Add(misc.ParseEpisode("4.0")) fmt.Println(a) a.Add(misc.ParseEpisode("4")) fmt.Println(a) a.Add(misc.ParseEpisode("5.1")) fmt.Println(a) a.Add(misc.ParseEpisode("6")) fmt.Println(a) // Output: // 1-3 // 1-4.0 // 1-4 // 1-4,5.1 // 1-4,5.1,6 }
func (adb *AniDB) parseMylistAnime(reply udpapi.APIReply) *MyListAnime { if reply.Code() != 312 { return nil } parts := strings.Split(reply.Lines()[1], "|") // Everything from index 7 on is pairs of group name on odd positions and episode list on even var groupParts []string if len(parts) > 7 { groupParts = parts[7:] } groupMap := make(GroupEpisodes, len(groupParts)/2) for i := 0; i+1 < len(groupParts); i += 2 { g := <-adb.GroupByName(groupParts[i]) if g == nil { continue } groupMap[g.GID] = misc.ParseEpisodeList(groupParts[i+1]) } return &MyListAnime{ EpisodesWithState: MyListStateMap{ MyListStateUnknown: misc.ParseEpisodeList(parts[2]), MyListStateHDD: misc.ParseEpisodeList(parts[3]), MyListStateCD: misc.ParseEpisodeList(parts[4]), MyListStateDeleted: misc.ParseEpisodeList(parts[5]), }, WatchedEpisodes: misc.ParseEpisodeList(parts[6]), EpisodesPerGroup: groupMap, } }
func ExampleEpisodeList_Simplify() { a := misc.ParseEpisodeList("1,2,3,5,10-14,13-15,,S3-S6,C7-C10,S1,S7,S8-") fmt.Println(a.Simplify()) // Output: 01-03,05,10-15,S1,S3-,C07-C10 }
func (adb *AniDB) parseFileResponse(f **File, reply udpapi.APIReply, calledFromFIDsByGID bool) bool { if reply.Error() != nil { return false } if reply.Truncated() { panic("Truncated") } uidChan := make(chan UID, 1) if adb.udp.credentials != nil { go func() { uidChan <- <-adb.GetUserUID(decrypt(adb.udp.credentials.username)) }() } else { uidChan <- 0 close(uidChan) } parts := strings.Split(reply.Lines()[1], "|") ints := make([]int64, len(parts)) for i, p := range parts { ints[i], _ = strconv.ParseInt(p, 10, 64) } partial := false rels := strings.Split(parts[5], "'") relList := make([]EID, 0, len(parts[5])) related := make(RelatedEpisodes, len(parts[5])) for _, rel := range rels { r := strings.Split(rel, ",") if len(r) < 2 { continue } eid, _ := strconv.ParseInt(r[0], 10, 32) pct, _ := strconv.ParseInt(r[1], 10, 32) relList = append(relList, EID(eid)) related[EID(eid)] = float32(pct) / 100 if pct != 100 { partial = true } } epno := misc.ParseEpisodeList(parts[24]) fid := FID(ints[0]) aid := AID(ints[1]) eid := EID(ints[2]) gid := GID(ints[3]) lid := LID(ints[4]) if !epno[0].Start.ContainsEpisodes(epno[0].End) || len(epno) > 1 || len(relList) > 0 { // epno is broken -- we need to sanitize it thisEp := <-adb.EpisodeByID(eid) bad := false if thisEp != nil { parts := make([]string, 1, len(relList)+1) parts[0] = thisEp.Episode.String() // everything after this SHOULD be cache hits now, unless this is somehow // linked with an EID from a different anime (*stares at Haruhi*). // We don't want to use eps from different AIDs anyway, so that makes // the job easier. // We check if the related episodes are all in sequence from this one. // If they are, we build a new epno with the sequence. Otherwise, // our epno will only have the primary episode. // gather the episode numbers for _, eid := range relList { if ep := eid.Episode(); ep != nil && ep.AID == thisEp.AID { parts = append(parts, ep.Episode.String()) } else { bad = true break } } test := misc.EpisodeList{} // only if we didn't break the loop if !bad { test = misc.ParseEpisodeList(strings.Join(parts, ",")) } if partial { if calledFromFIDsByGID { epno = test adb.Logger.Printf("UDP!!! FID %d is only part of episode %s with no complementary files", fid, epno) } else if len(test) == 1 && test[0].Start.Number == test[0].End.Number { fids := []int{} for fid := range adb.FIDsByGID(thisEp, gid) { fids = append(fids, int(fid)) } if len(fids) >= 1 && fids[0] == 0 { fids = fids[1:] // Only entry was API error if len(fids) == 0 { return false } } sort.Sort(sort.IntSlice(fids)) idx := sort.SearchInts(fids, int(fid)) if idx == len(fids) { panic(fmt.Sprintf("FID %d couldn't locate itself", fid)) } epno = test // equate pointers epno[0].End = epno[0].Start epno[0].Start.Parts = len(fids) epno[0].Start.Part = idx } else { panic(fmt.Sprintf("Don't know what to do with partial episode %s (EID %d)", test, eid)) } } else { // if they're all in sequence, then we'll only have a single range in the list if len(test) == 1 { epno = test } else { // use only the primary epno then epno = misc.ParseEpisodeList(thisEp.Episode.String()) } } } } epstr := epno.String() if len(epno) == 1 && epno[0].Type == misc.EpisodeTypeCredits && epno[0].Len() == 1 { typ := "" n := 0 if ep := <-adb.EpisodeByID(eid); ep == nil { } else if m := opedRE.FindStringSubmatch(ep.Titles["en"]); len(m) > 2 { num, err := strconv.ParseInt(m[2], 10, 32) if err == nil { n = int(num) } typ = m[1] } gobi := fmt.Sprintf("%d", n) if n == 0 { gobi = "" } switch typ { case "Opening": epstr = "OP" + gobi case "Ending": epstr = "ED" + gobi } } version := FileVersion(1) switch i := ints[7]; { case i&stateV5 != 0: version = 5 case i&stateV4 != 0: version = 4 case i&stateV3 != 0: version = 3 case i&stateV2 != 0: version = 2 } codecs := strings.Split(parts[14], "'") bitrates := strings.Split(parts[15], "'") alangs := strings.Split(parts[20], "'") streams := make([]AudioStream, len(codecs)) for i := range streams { br, _ := strconv.ParseInt(bitrates[i], 10, 32) streams[i] = AudioStream{ Bitrate: int(br), Codec: sanitizeCodec(codecs[i]), Language: Language(alangs[i]), } } sl := strings.Split(parts[21], "'") slangs := make([]Language, len(sl)) for i := range sl { slangs[i] = Language(sl[i]) } depth := int(ints[12]) if depth == 0 { depth = 8 } res := strings.Split(parts[18], "x") width, _ := strconv.ParseInt(res[0], 10, 32) height, _ := strconv.ParseInt(res[1], 10, 32) video := VideoInfo{ Bitrate: int(ints[17]), Codec: sanitizeCodec(parts[16]), ColorDepth: depth, Resolution: image.Rect(0, 0, int(width), int(height)), } lidMap := LIDMap{} if *f != nil { lidMap = (*f).LID } uid := <-uidChan if uid != 0 { lidMap[uid] = lid } *f = &File{ FID: fid, AID: aid, EID: eid, GID: gid, LID: lidMap, EpisodeString: epstr, EpisodeNumber: epno, RelatedEpisodes: related, Deprecated: ints[6] != 0, CRCMatch: ints[7]&stateCRCOK != 0, BadCRC: ints[7]&stateCRCERR != 0, Version: version, Uncensored: ints[7]&stateUncensored != 0, Censored: ints[7]&stateCensored != 0, Incomplete: video.Resolution.Empty(), Filesize: ints[8], Ed2kHash: parts[9], SHA1Hash: parts[10], CRC32: parts[11], Source: FileSource(parts[13]), AudioStreams: streams, SubtitleLanguages: slangs, VideoInfo: video, FileExtension: parts[19], Length: time.Duration(ints[22]) * time.Second, AirDate: time.Unix(ints[23], 0), } return true }