This repository has been archived by the owner on Jul 29, 2020. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sitestructure.go
182 lines (148 loc) · 4.9 KB
/
sitestructure.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package insidescraper
import (
"encoding/json"
"errors"
)
// Site contains all site data.
type Site struct {
Sections map[string]SiteSection
Lessons map[string]Lesson
// IDs of all top level sections.
TopLevel []TopItem
}
// SiteSection describes a section of a site.
type SiteSection struct {
*SiteData
ID string
// Sections contains the ids of all sub sections
Sections []string
// IDs of all lessons in this section.
Lessons []string
// AudioCount contains the total number of audio classes contained in this section,
// including all descendant sections.
AudioCount int
}
// TopItem is a top level item on the site.
type TopItem struct {
ID string
Image string
}
// Lesson describes one lesson. It may contain multiple classes.
type Lesson struct {
*SiteData
// ID is the URL of the lessons, if they are from their own page.
ID string
Audio []Media
}
// Media contains information about a particular piece of media.
type Media struct {
// Note that a media item will *only* have it's own PDF if it was converted from a lesson.
*SiteData
Source string
}
// SiteData is a base type used by other site structures.
type SiteData struct {
Title string
Description string
// PDFs can pop up at any level.
// For example, sometimes a section has a pdf for it. This usually (probably always) happens
// when the section contains only lessons, when it will anyway be converted to a lesson.
// See https://insidechassidus.org/thought-and-history/123-kabbala-and-philosophy-series/1699-chassidus-understanding-what-can-be-understood-of-g-dliness/section-one-before-logic
Pdf []string
}
// ConvertToLesson converts the section to a lesson if it only contains single-audio lessons.
// Returns an error if it can't be done.
func (site *Site) ConvertToLesson(sectionID string) error {
section := site.Sections[sectionID]
// Make sure it doesn't contain sections.
if len(section.Sections) > 0 {
return errors.New("Contains sections")
}
switch len(section.Lessons) {
case 0:
return errors.New("Does not contain any lessons")
case 1:
// The section is really just a single lesson. Get rid of the pretend section.
delete(site.Sections, sectionID)
/*
* Change the ID and key of the lesson to the old section ID.
* This will allow any references to it to be found and updated.
*/
lesson := site.Lessons[section.Lessons[0]]
oldLessonID := lesson.ID
lesson.ID = sectionID
site.Lessons[lesson.ID] = lesson
// The lesson is no longer locatable with it's old ID.
delete(site.Lessons, oldLessonID)
return nil
default:
// A section can only be converted to a lesson if all of it's lessons are single audio files.
for _, lessonID := range section.Lessons {
if lesson, exists := site.Lessons[lessonID]; exists {
if len(lesson.Audio) > 1 {
return errors.New("Contains complex lessons: " + lesson.Title + "," + sectionID)
}
} else {
panic("Hey, why doesn't " + lessonID + " (referenced by " + section.ID + ")" + " exist?")
}
}
}
// Move section over to lesson.
site.Lessons[sectionID] = site.getLessonFromSection(sectionID)
delete(site.Sections, sectionID)
return nil
}
// Creates one lesson from a section which consists only of single media lessons.
func (site *Site) getLessonFromSection(sectionID string) Lesson {
section := site.Sections[sectionID]
// Create lesson.
newLesson := Lesson{
SiteData: section.SiteData,
ID: section.ID,
Audio: make([]Media, 0, len(section.Lessons)),
}
// Move the section's lessons into media on this one, new lesson.
for _, lessonID := range section.Lessons {
lessonToConvert := site.Lessons[lessonID]
if len(lessonToConvert.Audio) != 0 {
newLesson.Audio = append(newLesson.Audio, Media{
// Note that SiteData also includes PDF URL.
SiteData: lessonToConvert.SiteData,
Source: lessonToConvert.Audio[0].Source,
})
}
// Delete the old, single media lesson.
delete(site.Lessons, lessonID)
}
return newLesson
}
func (i *Media) UnmarshalJSON(data []byte) error {
// See https://stackoverflow.com/a/43178272
type forceDefaultUnmarshalType *Media
json.Unmarshal(data, forceDefaultUnmarshalType(i))
// See https://stackoverflow.com/a/54624012
siteData := &SiteData{}
json.Unmarshal(data, siteData)
i.SiteData = siteData
return nil
}
func (i *SiteSection) UnmarshalJSON(data []byte) error {
// See https://stackoverflow.com/a/43178272
type forceDefaultUnmarshalType *SiteSection
json.Unmarshal(data, forceDefaultUnmarshalType(i))
// See https://stackoverflow.com/a/54624012
siteData := &SiteData{}
json.Unmarshal(data, siteData)
i.SiteData = siteData
return nil
}
func (i *Lesson) UnmarshalJSON(data []byte) error {
// See https://stackoverflow.com/a/43178272
type forceDefaultUnmarshalType *Lesson
json.Unmarshal(data, forceDefaultUnmarshalType(i))
// See https://stackoverflow.com/a/54624012
siteData := &SiteData{}
json.Unmarshal(data, siteData)
i.SiteData = siteData
return nil
}