From ca8f1f51e5639644ce00ef4ab2ba14db56d40948 Mon Sep 17 00:00:00 2001 From: Abhinav R <76396917+Abhinav-ark@users.noreply.github.com> Date: Sat, 5 Oct 2024 12:20:48 +0530 Subject: [PATCH 1/3] Initial Usable Version --- cmd/configs.go | 14 +++++++++ cmd/helpers.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++ cmd/logo.go | 12 +++++++ cmd/root.go | 64 +++++++++++++++++++++++++++++++++++++ cmd/semChoose.go | 72 ++++++++++++++++++++++++++++++++++++++++++ cmd/semTable.go | 72 ++++++++++++++++++++++++++++++++++++++++++ cmd/version.go | 19 +++++++++++ cmd/year.go | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 19 +++++++++++ go.sum | 14 +++++++++ main.go | 10 ++++++ 11 files changed, 458 insertions(+) create mode 100644 cmd/configs.go create mode 100644 cmd/helpers.go create mode 100644 cmd/logo.go create mode 100644 cmd/root.go create mode 100644 cmd/semChoose.go create mode 100644 cmd/semTable.go create mode 100644 cmd/version.go create mode 100644 cmd/year.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/cmd/configs.go b/cmd/configs.go new file mode 100644 index 0000000..2d50fe5 --- /dev/null +++ b/cmd/configs.go @@ -0,0 +1,14 @@ +package cmd + +const base_url = "http://dspace.amritanet.edu:8080" + +const course_url = base_url + "/xmlui/handle/123456789/" + +const code_btech = "150" +const code_ba_communication = "893" +const code_ma_communication = "894" +const code_integrated_msc_ma = "903" +const code_mca = "331" +const code_msw = "393" +const code_mtech = "279" + diff --git a/cmd/helpers.go b/cmd/helpers.go new file mode 100644 index 0000000..3c5d438 --- /dev/null +++ b/cmd/helpers.go @@ -0,0 +1,80 @@ +package cmd + +import ( + "fmt" + "log" + "github.com/anaskhan96/soup" + "os/exec" + "runtime" +) + +// fetchHTML - fetches and parses HTML from the given URL +func fetchHTML(url string) string { + doc, err := soup.Get(url) + if err != nil { + fmt.Println("Error fetching the URL. Make sure you're connected to Amrita WiFi or VPN.") + return "" + } + return doc +} + + +// openBrowser - opens a URL in the default web browser +func openBrowser(url string) { + var err error + switch runtime.GOOS { + case "linux": + err = exec.Command("xdg-open", url).Start() + case "windows": + err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() + case "darwin": + err = exec.Command("open", url).Start() + } + if err != nil { + log.Fatal(err) + } +} + +// Stack implementation using Go slices +type Stack struct { + items []string +} + +// Push - adds an item to the stack +func (s *Stack) Push(item string) { + s.items = append(s.items, item) +} + +// Pop - removes and returns the top item from the stack +func (s *Stack) Pop() string { + if len(s.items) == 0 { + return "" + } + item := s.items[len(s.items)-1] + s.items = s.items[:len(s.items)-1] + return item +} + +// IsEmpty - returns true if the stack is empty +func (s *Stack) IsEmpty() bool { + return len(s.items) == 0 +} + +// Peek - returns the top item without removing it +func (s *Stack) Peek() string { + if len(s.items) == 0 { + return "" + } + return s.items[len(s.items)-1] +} + +// NewStack - creates a new stack +func NewStack() *Stack { + return &Stack{} +} + +var stack = NewStack() + + + + diff --git a/cmd/logo.go b/cmd/logo.go new file mode 100644 index 0000000..691bc1f --- /dev/null +++ b/cmd/logo.go @@ -0,0 +1,12 @@ +package cmd + +const logo_ascii string = ` + __ __ _____ _____ _______ _______ ______ + /\ | \/ | __ \|_ _|__ __|/\ | __ \ \ / / __ \ + / \ | \ / | |__) | | | | | / \ | |__) \ \_/ / | | | + / /\ \ | |\/| | _ / | | | | / /\ \ | ___/ \ /| | | | + / ____ \| | | | | \ \ _| |_ | |/ ____ \ | | | | | |__| | + /_/ \_\_| |_|_| \_\_____| |_/_/ \_\ |_| |_| \___\_\ + +` + diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..e06aa00 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,64 @@ +package cmd + +import ( + "fmt" + "os" + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "ampyq", + Short: "Amrita PYQ CLI", + Long: `A CLI application to access Amrita Repository for previous year question papers.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Print(logo_ascii) + start() + }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +// start function - equivalent to start() in Python +func start() { + fmt.Println("Available Courses:\n") + fmt.Println("1. B.Tech") + fmt.Println("2. BA Communication") + fmt.Println("3. MA Communication") + fmt.Println("4. Integrated MSc & MA") + fmt.Println("5. MCA") + fmt.Println("6. MSW") + fmt.Println("7. M.Tech") + fmt.Println("8. Exit") + + var choice int + fmt.Printf("\nEnter your choice: ") + fmt.Scanln(&choice) + + switch choice { + case 1: + semTable(course_url+code_btech) + case 2: + semTable(course_url+code_ba_communication) + case 3: + semTable(course_url+code_ma_communication) + case 4: + semTable(course_url+code_integrated_msc_ma) + case 5: + semTable(course_url+code_mca) + case 6: + semTable(course_url+code_msw) + case 7: + semTable(course_url+code_mtech) + case 8: + fmt.Println("Goodbye!") + os.Exit(0) + default: + fmt.Println("Invalid option!") + } +} \ No newline at end of file diff --git a/cmd/semChoose.go b/cmd/semChoose.go new file mode 100644 index 0000000..dd61cb9 --- /dev/null +++ b/cmd/semChoose.go @@ -0,0 +1,72 @@ +package cmd + +import ( + "fmt" + "github.com/anaskhan96/soup" +) + +func semChoose(url string) { + fmt.Println("Fetching assesments...") + params_url := url + resp := fetchHTML(url) // Fetch the HTML content + + // Check if the response is empty + if resp == "" { + fmt.Println("Failed to fetch the HTML content. Exiting.") + return + } + + // Parse the HTML content using soup + doc := soup.HTMLParse(resp) + div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") + + if div.Error != nil { + fmt.Println("No assesments found on the page.") + return + } + + ul := div.FindAll("ul") + li := ul[0].FindAll("li") + + if len(ul)>1 { + li = ul[1].FindAll("li") + } else { + li = ul[0].FindAll("li") + } + + // Display the found items + fmt.Printf("No\tSemesters\n") + for i, link := range li { + a := link.Find("a") + if a.Error == nil { + span := a.Find("span") + if span.Error == nil { + fmt.Printf("%d\t%s\n", i+1, span.Text()) // Extract the text from the span element + } + } + } + + // Option to add "Back" + fmt.Printf("%d\tBack\n", len(li)+1) + + + for { + var ch int + fmt.Print("\nEnter your assesment: ") + fmt.Scanln(&ch) + + if ch > 0 && ch <= len(li) { + url = base_url + li[ch-1].Find("a").Attrs()["href"] + break + } else if ch == len(li)+1 { + semTable(stack.Pop()) + } else { + fmt.Println("Please enter a valid input!") + } + } + + // append to stack + stack.Push(params_url) + + year(url) +} \ No newline at end of file diff --git a/cmd/semTable.go b/cmd/semTable.go new file mode 100644 index 0000000..92c706d --- /dev/null +++ b/cmd/semTable.go @@ -0,0 +1,72 @@ +package cmd + +import ( + "fmt" + "github.com/anaskhan96/soup" +) + +// semTable function - equivalent to your Python code +func semTable(url string) { + fmt.Println("Fetching semesters...") + resp := fetchHTML(url) // Fetch the HTML content + + // Check if the response is empty + if resp == "" { + fmt.Println("Failed to fetch the HTML content. Exiting.") + return + } + + // Parse the HTML content using soup + doc := soup.HTMLParse(resp) + div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") + + if div.Error != nil { + fmt.Println("No semesters found on the page.") + return + } + + ul := div.Find("ul") + li := ul.FindAll("li") + + if len(li) == 0 { + fmt.Println("No semesters found on the page.") + return + } + + // Display the found items + fmt.Printf("No\tSemesters\n") + for i, link := range li { + a := link.Find("a") + if a.Error == nil { + span := a.Find("span") + if span.Error == nil { + fmt.Printf("%d\t%s\n", i+1, span.Text()) // Extract the text from the span element + } + } + } + + // Option to add "Back" + fmt.Printf("%d\tBack\n", len(li)+1) + + // append to stack + stack.Push(url) + + + for { + var ch int + fmt.Print("\nEnter your semester: ") + fmt.Scanln(&ch) + + if ch > 0 && ch <= len(li) { + url := base_url + li[ch-1].Find("a").Attrs()["href"] + semChoose(url) + break + } else if ch == len(li)+1 { + start() + break + } else { + fmt.Println("Please enter a valid input!") + } + } + +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 0000000..aa1bfe5 --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(versionCmd) +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version number of ampyq", + Long: `Displays version of ampyq installed on the system.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Amrita Previous Year Questions v0.0.1-alpha") + }, +} \ No newline at end of file diff --git a/cmd/year.go b/cmd/year.go new file mode 100644 index 0000000..1b7b4cf --- /dev/null +++ b/cmd/year.go @@ -0,0 +1,82 @@ +package cmd + +import ( + "fmt" + "os" + "github.com/anaskhan96/soup" +) + + +func year(url string) { + fmt.Println("Fetching...") + year_url := url + res := fetchHTML(url) + + // Check if the response is empty + if res == "" { + fmt.Println("Failed to fetch the HTML content. Exiting.") + return + } + + // Parse the HTML content using soup + doc := soup.HTMLParse(res) + div := doc.Find("div", "xmlns","http://di.tamu.edu/DRI/1.0/") + + ul := div.Find("ul") + li := ul.Find("li") + hyper := li.Find("a").Attrs()["href"] + + url = base_url + url += hyper + page := fetchHTML(url) + + doc = soup.HTMLParse(page) + div = doc.Find("div", "class","file-list") + + subdiv := div.FindAll("div","class","file-wrapper") + + // Display the found items + fmt.Printf("No\tFiles\n") + for i, item := range subdiv { + title := item.FindAll("div") + indiv := title[1].Find("div") + span := indiv.FindAll("span") + if span[0].Error == nil { + fmt.Printf("%d\t%s\n", i+1, span[1].Attrs()["title"]) // Extract the text from the span element + } + } + + // Option to add "Back" + fmt.Printf("%d\tBack\n", len(subdiv)+1) + + for { + var ch int + fmt.Print("\nEnter your choice: ") + fmt.Scanln(&ch) + + if ch > 0 && ch <= len(subdiv) { + title := subdiv[ch-1].FindAll("div") + link := title[0].Find("a").Attrs()["href"] + url = base_url + link + break + } else if ch == len(subdiv)+1 { + semChoose(stack.Pop()) + } else { + fmt.Println("Please enter a valid input!") + } + } + + fmt.Println("Please wait until browser opens !") + openBrowser(url) + + var ch int + fmt.Println("Do you want to continue ? \nPress 1 for Yes and 0 for No : "); + fmt.Scanln(&ch) + + if ch == 0 { + fmt.Println("Exiting...") + os.Exit(0) + } else { + year(year_url) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..17cc7fd --- /dev/null +++ b/go.mod @@ -0,0 +1,19 @@ +module amrita_pyq + +go 1.23 + +toolchain go1.23.1 + +require ( + github.com/anaskhan96/soup v1.2.5 + github.com/spf13/cobra v1.8.1 +) + +require ( + github.com/PuerkitoBio/goquery v1.10.0 // indirect + github.com/andybalholm/cascadia v1.3.2 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/text v0.18.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ee993ca --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4= +github.com/anaskhan96/soup v1.2.5 h1:V/FHiusdTrPrdF4iA1YkVxsOpdNcgvqT1hG+YtcZ5hM= +github.com/anaskhan96/soup v1.2.5/go.mod h1:6YnEp9A2yywlYdM4EgDz9NEHclocMepEtku7wg6Cq3s= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= diff --git a/main.go b/main.go new file mode 100644 index 0000000..5bbba78 --- /dev/null +++ b/main.go @@ -0,0 +1,10 @@ +package main + +import ( + "amrita_pyq/cmd" +) + +func main() { + cmd.Execute() +} + From ccd38cf285586c79191d07daadcfb82ee7ff02e1 Mon Sep 17 00:00:00 2001 From: Abhinav R <76396917+Abhinav-ark@users.noreply.github.com> Date: Sun, 6 Oct 2024 01:12:32 +0530 Subject: [PATCH 2/3] Change static course urls to dynamically fetched course urls. --- cmd/configs.go | 16 +++------- cmd/helpers.go | 6 +--- cmd/logo.go | 2 +- cmd/root.go | 81 +++++++++++++++++++++++++++--------------------- cmd/semChoose.go | 8 ++--- cmd/semTable.go | 8 ++--- cmd/year.go | 5 ++- main.go | 3 +- 8 files changed, 63 insertions(+), 66 deletions(-) diff --git a/cmd/configs.go b/cmd/configs.go index 2d50fe5..fdf0fbd 100644 --- a/cmd/configs.go +++ b/cmd/configs.go @@ -1,14 +1,8 @@ package cmd -const base_url = "http://dspace.amritanet.edu:8080" - -const course_url = base_url + "/xmlui/handle/123456789/" - -const code_btech = "150" -const code_ba_communication = "893" -const code_ma_communication = "894" -const code_integrated_msc_ma = "903" -const code_mca = "331" -const code_msw = "393" -const code_mtech = "279" +const ( + BASE_URL = "http://dspace.amritanet.edu:8080" + COURSE_URL = BASE_URL + "/xmlui/handle/123456789/" + COURSE_LIST_URL = COURSE_URL + "16" +) diff --git a/cmd/helpers.go b/cmd/helpers.go index 3c5d438..89a1906 100644 --- a/cmd/helpers.go +++ b/cmd/helpers.go @@ -73,8 +73,4 @@ func NewStack() *Stack { return &Stack{} } -var stack = NewStack() - - - - +var stack = NewStack() \ No newline at end of file diff --git a/cmd/logo.go b/cmd/logo.go index 691bc1f..b1eb521 100644 --- a/cmd/logo.go +++ b/cmd/logo.go @@ -1,6 +1,6 @@ package cmd -const logo_ascii string = ` +const LOGO_ASCII string = ` __ __ _____ _____ _______ _______ ______ /\ | \/ | __ \|_ _|__ __|/\ | __ \ \ / / __ \ / \ | \ / | |__) | | | | | / \ | |__) \ \_/ / | | | diff --git a/cmd/root.go b/cmd/root.go index e06aa00..82f1ea7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,9 +1,10 @@ package cmd import ( - "fmt" - "os" - "github.com/spf13/cobra" + "fmt" + "os" + "github.com/anaskhan96/soup" + "github.com/spf13/cobra" ) var rootCmd = &cobra.Command{ @@ -11,7 +12,7 @@ var rootCmd = &cobra.Command{ Short: "Amrita PYQ CLI", Long: `A CLI application to access Amrita Repository for previous year question papers.`, Run: func(cmd *cobra.Command, args []string) { - fmt.Print(logo_ascii) + fmt.Print(LOGO_ASCII) start() }, } @@ -26,39 +27,47 @@ func Execute() { // start function - equivalent to start() in Python func start() { - fmt.Println("Available Courses:\n") - fmt.Println("1. B.Tech") - fmt.Println("2. BA Communication") - fmt.Println("3. MA Communication") - fmt.Println("4. Integrated MSc & MA") - fmt.Println("5. MCA") - fmt.Println("6. MSW") - fmt.Println("7. M.Tech") - fmt.Println("8. Exit") + fmt.Println("Fetching Courses...") + res := fetchHTML(COURSE_LIST_URL) + fmt.Println("Available Courses:") - var choice int - fmt.Printf("\nEnter your choice: ") - fmt.Scanln(&choice) + // Check if the response is empty + if res == "" { + fmt.Println("Failed to fetch the HTML content. Exiting.") + return + } + + // Parse the HTML content using soup + doc := soup.HTMLParse(res) + div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") + + subs := div.FindAll("div","class","artifact-title") + + for i, item := range subs { + sub := item.Find("span") + if sub.Error == nil { + fmt.Printf("%d.\t%s\n", i+1, sub.Text()) + } + } + + // Option to quit. + fmt.Printf("%d.\tQuit\n", len(subs)+1) + + for { + var ch int + fmt.Printf("\nEnter your choice: ") + fmt.Scanln(&ch) - switch choice { - case 1: - semTable(course_url+code_btech) - case 2: - semTable(course_url+code_ba_communication) - case 3: - semTable(course_url+code_ma_communication) - case 4: - semTable(course_url+code_integrated_msc_ma) - case 5: - semTable(course_url+code_mca) - case 6: - semTable(course_url+code_msw) - case 7: - semTable(course_url+code_mtech) - case 8: - fmt.Println("Goodbye!") - os.Exit(0) - default: - fmt.Println("Invalid option!") + if ch > 0 && ch <= len(subs) { + a := subs[ch-1].Find("a") + path := a.Attrs()["href"] + url := BASE_URL + path + semTable(url) + } else if ch == len(subs)+1 { + fmt.Println("Goodbye!") + os.Exit(0) + } else { + fmt.Println("Please enter a valid input!") + } } } \ No newline at end of file diff --git a/cmd/semChoose.go b/cmd/semChoose.go index dd61cb9..d9e3c72 100644 --- a/cmd/semChoose.go +++ b/cmd/semChoose.go @@ -8,16 +8,16 @@ import ( func semChoose(url string) { fmt.Println("Fetching assesments...") params_url := url - resp := fetchHTML(url) // Fetch the HTML content + res := fetchHTML(url) // Fetch the HTML content // Check if the response is empty - if resp == "" { + if res == "" { fmt.Println("Failed to fetch the HTML content. Exiting.") return } // Parse the HTML content using soup - doc := soup.HTMLParse(resp) + doc := soup.HTMLParse(res) div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") if div.Error != nil { @@ -56,7 +56,7 @@ func semChoose(url string) { fmt.Scanln(&ch) if ch > 0 && ch <= len(li) { - url = base_url + li[ch-1].Find("a").Attrs()["href"] + url = BASE_URL + li[ch-1].Find("a").Attrs()["href"] break } else if ch == len(li)+1 { semTable(stack.Pop()) diff --git a/cmd/semTable.go b/cmd/semTable.go index 92c706d..339e7ac 100644 --- a/cmd/semTable.go +++ b/cmd/semTable.go @@ -8,16 +8,16 @@ import ( // semTable function - equivalent to your Python code func semTable(url string) { fmt.Println("Fetching semesters...") - resp := fetchHTML(url) // Fetch the HTML content + res := fetchHTML(url) // Fetch the HTML content // Check if the response is empty - if resp == "" { + if res == "" { fmt.Println("Failed to fetch the HTML content. Exiting.") return } // Parse the HTML content using soup - doc := soup.HTMLParse(resp) + doc := soup.HTMLParse(res) div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") if div.Error != nil { @@ -58,7 +58,7 @@ func semTable(url string) { fmt.Scanln(&ch) if ch > 0 && ch <= len(li) { - url := base_url + li[ch-1].Find("a").Attrs()["href"] + url := BASE_URL + li[ch-1].Find("a").Attrs()["href"] semChoose(url) break } else if ch == len(li)+1 { diff --git a/cmd/year.go b/cmd/year.go index 1b7b4cf..a627e38 100644 --- a/cmd/year.go +++ b/cmd/year.go @@ -26,8 +26,7 @@ func year(url string) { li := ul.Find("li") hyper := li.Find("a").Attrs()["href"] - url = base_url - url += hyper + url = BASE_URL + hyper page := fetchHTML(url) doc = soup.HTMLParse(page) @@ -57,7 +56,7 @@ func year(url string) { if ch > 0 && ch <= len(subdiv) { title := subdiv[ch-1].FindAll("div") link := title[0].Find("a").Attrs()["href"] - url = base_url + link + url = BASE_URL + link break } else if ch == len(subdiv)+1 { semChoose(stack.Pop()) diff --git a/main.go b/main.go index 5bbba78..09b7ef0 100644 --- a/main.go +++ b/main.go @@ -6,5 +6,4 @@ import ( func main() { cmd.Execute() -} - +} \ No newline at end of file From a4902851a9686bdc107a1b34507c8098757b7132 Mon Sep 17 00:00:00 2001 From: Abhinav R <76396917+Abhinav-ark@users.noreply.github.com> Date: Wed, 9 Oct 2024 23:30:01 +0530 Subject: [PATCH 3/3] Modularized code, created "requestClient" to scrape content seperately --- cmd/helpers.go | 54 +++------------- cmd/model.go | 7 ++ cmd/requestClient.go | 151 +++++++++++++++++++++++++++++++++++++++++++ cmd/root.go | 35 ++++------ cmd/semChoose.go | 44 +++---------- cmd/semTable.go | 50 ++++---------- cmd/stack.go | 41 ++++++++++++ cmd/year.go | 47 ++++---------- 8 files changed, 251 insertions(+), 178 deletions(-) create mode 100644 cmd/model.go create mode 100644 cmd/requestClient.go create mode 100644 cmd/stack.go diff --git a/cmd/helpers.go b/cmd/helpers.go index 89a1906..c62e947 100644 --- a/cmd/helpers.go +++ b/cmd/helpers.go @@ -8,18 +8,20 @@ import ( "runtime" ) -// fetchHTML - fetches and parses HTML from the given URL -func fetchHTML(url string) string { +// Fetches and parses HTML from the given URL. +func fetchHTML(url string) (string, error) { doc, err := soup.Get(url) + if err != nil { fmt.Println("Error fetching the URL. Make sure you're connected to Amrita WiFi or VPN.") - return "" + return "", err } - return doc + + return doc, nil } -// openBrowser - opens a URL in the default web browser +// Opens a URL in the default web browser. func openBrowser(url string) { var err error switch runtime.GOOS { @@ -33,44 +35,4 @@ func openBrowser(url string) { if err != nil { log.Fatal(err) } -} - -// Stack implementation using Go slices -type Stack struct { - items []string -} - -// Push - adds an item to the stack -func (s *Stack) Push(item string) { - s.items = append(s.items, item) -} - -// Pop - removes and returns the top item from the stack -func (s *Stack) Pop() string { - if len(s.items) == 0 { - return "" - } - item := s.items[len(s.items)-1] - s.items = s.items[:len(s.items)-1] - return item -} - -// IsEmpty - returns true if the stack is empty -func (s *Stack) IsEmpty() bool { - return len(s.items) == 0 -} - -// Peek - returns the top item without removing it -func (s *Stack) Peek() string { - if len(s.items) == 0 { - return "" - } - return s.items[len(s.items)-1] -} - -// NewStack - creates a new stack -func NewStack() *Stack { - return &Stack{} -} - -var stack = NewStack() \ No newline at end of file +} \ No newline at end of file diff --git a/cmd/model.go b/cmd/model.go new file mode 100644 index 0000000..cd5e095 --- /dev/null +++ b/cmd/model.go @@ -0,0 +1,7 @@ +package cmd + +type resource struct { + name string + path string +} + diff --git a/cmd/requestClient.go b/cmd/requestClient.go new file mode 100644 index 0000000..03cf246 --- /dev/null +++ b/cmd/requestClient.go @@ -0,0 +1,151 @@ +package cmd + +import ( + "errors" + "github.com/anaskhan96/soup" +) + +var htmlFetchErr error = errors.New("failed to fetch the HTML content") + +func getCoursesReq(url string) ([]resource, error) { + + res, err := fetchHTML(url) + + if err != nil { + return nil, htmlFetchErr + } + + doc := soup.HTMLParse(res) + div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") + + subs := div.FindAll("div","class","artifact-title") + + var subjects []resource + + for _, item := range subs { + sub := item.Find("span") + a := item.Find("a") + path := a.Attrs()["href"] + subject := resource{sub.Text(), path} + subjects = append(subjects, subject) + } + + return subjects, nil +} + + +func semChooseReq(url string) ([]resource ,error) { + + res, err := fetchHTML(url) + + if err != nil { + return nil, htmlFetchErr + } + + doc := soup.HTMLParse(res) + div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") + + if div.Error != nil { + return nil, errors.New("No assesments found on the page.") + } + + ul := div.FindAll("ul") + li := ul[0].FindAll("li") + + if len(ul)>1 { + li = ul[1].FindAll("li") + } else { + li = ul[0].FindAll("li") + } + + var assesments []resource + + for _, link := range li { + a := link.Find("a") + span := a.Find("span") + path := link.Find("a").Attrs()["href"] + assesment := resource{span.Text(), path} + assesments = append(assesments, assesment) + } + + return assesments, nil +} + +func semTableReq(url string) ([]resource, error) { + + res, err := fetchHTML(url) + + if err != nil { + return nil, htmlFetchErr + } + + doc := soup.HTMLParse(res) + div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") + + if div.Error != nil { + return nil, errors.New("No semesters found on the page.") + } + + ul := div.Find("ul") + li := ul.FindAll("li") + + if len(li) == 0 { + return nil, errors.New("No semesters found on the page.") + } + + var semesters []resource + + for _, link := range li { + a := link.Find("a") + span := a.Find("span") + path := link.Find("a").Attrs()["href"] + semester := resource{span.Text(), path} + semesters = append(semesters, semester) + } + + return semesters, nil + +} + +func yearReq(url string) ([]resource, error) { + + res, err := fetchHTML(url) + + if err != nil { + return nil, htmlFetchErr + } + + doc := soup.HTMLParse(res) + div := doc.Find("div", "xmlns","http://di.tamu.edu/DRI/1.0/") + + ul := div.Find("ul") + li := ul.Find("li") + hyper := li.Find("a").Attrs()["href"] + + url = BASE_URL + hyper + page,err := fetchHTML(url) + + if err != nil { + return nil, htmlFetchErr + } + + doc = soup.HTMLParse(page) + div = doc.Find("div", "class","file-list") + + subdiv := div.FindAll("div","class","file-wrapper") + + var files []resource + + for _, item := range subdiv { + title := item.FindAll("div") + indiv := title[1].Find("div") + span := indiv.FindAll("span") + fileName := span[1].Attrs()["title"] + path := title[0].Find("a").Attrs()["href"] + file := resource{fileName, path} + files = append(files, file) + } + + return files, nil + +} diff --git a/cmd/root.go b/cmd/root.go index 82f1ea7..26e09cd 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,7 +3,7 @@ package cmd import ( "fmt" "os" - "github.com/anaskhan96/soup" + "github.com/spf13/cobra" ) @@ -28,42 +28,33 @@ func Execute() { // start function - equivalent to start() in Python func start() { fmt.Println("Fetching Courses...") - res := fetchHTML(COURSE_LIST_URL) - fmt.Println("Available Courses:") - // Check if the response is empty - if res == "" { - fmt.Println("Failed to fetch the HTML content. Exiting.") + subjects, err := getCoursesReq(COURSE_LIST_URL) + + if err != nil { + fmt.Errorf(err.Error()) return } - // Parse the HTML content using soup - doc := soup.HTMLParse(res) - div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") - - subs := div.FindAll("div","class","artifact-title") - - for i, item := range subs { - sub := item.Find("span") - if sub.Error == nil { - fmt.Printf("%d.\t%s\n", i+1, sub.Text()) - } + fmt.Println("Available Courses:") + + for i, subject := range subjects { + fmt.Printf("%d.\t%s\n", i+1, subject.name) } // Option to quit. - fmt.Printf("%d.\tQuit\n", len(subs)+1) + fmt.Printf("%d.\tQuit\n", len(subjects)+1) for { var ch int fmt.Printf("\nEnter your choice: ") fmt.Scanln(&ch) - if ch > 0 && ch <= len(subs) { - a := subs[ch-1].Find("a") - path := a.Attrs()["href"] + if ch > 0 && ch <= len(subjects) { + path := subjects[ch-1].path url := BASE_URL + path semTable(url) - } else if ch == len(subs)+1 { + } else if ch == len(subjects)+1 { fmt.Println("Goodbye!") os.Exit(0) } else { diff --git a/cmd/semChoose.go b/cmd/semChoose.go index d9e3c72..375f086 100644 --- a/cmd/semChoose.go +++ b/cmd/semChoose.go @@ -2,63 +2,37 @@ package cmd import ( "fmt" - "github.com/anaskhan96/soup" ) func semChoose(url string) { fmt.Println("Fetching assesments...") params_url := url - res := fetchHTML(url) // Fetch the HTML content - - // Check if the response is empty - if res == "" { - fmt.Println("Failed to fetch the HTML content. Exiting.") - return - } - // Parse the HTML content using soup - doc := soup.HTMLParse(res) - div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") + assesments, err := semChooseReq(url) - if div.Error != nil { - fmt.Println("No assesments found on the page.") + if err != nil { + fmt.Errorf(err.Error()) return } - ul := div.FindAll("ul") - li := ul[0].FindAll("li") - - if len(ul)>1 { - li = ul[1].FindAll("li") - } else { - li = ul[0].FindAll("li") - } - // Display the found items fmt.Printf("No\tSemesters\n") - for i, link := range li { - a := link.Find("a") - if a.Error == nil { - span := a.Find("span") - if span.Error == nil { - fmt.Printf("%d\t%s\n", i+1, span.Text()) // Extract the text from the span element - } - } + for i, assesment := range assesments { + fmt.Printf("%d\t%s\n", i+1, assesment.name) // Extract the text from the span element } // Option to add "Back" - fmt.Printf("%d\tBack\n", len(li)+1) - + fmt.Printf("%d\tBack\n", len(assesments)+1) for { var ch int fmt.Print("\nEnter your assesment: ") fmt.Scanln(&ch) - if ch > 0 && ch <= len(li) { - url = BASE_URL + li[ch-1].Find("a").Attrs()["href"] + if ch > 0 && ch <= len(assesments) { + url = BASE_URL + assesments[ch-1].path break - } else if ch == len(li)+1 { + } else if ch == len(assesments)+1 { semTable(stack.Pop()) } else { fmt.Println("Please enter a valid input!") diff --git a/cmd/semTable.go b/cmd/semTable.go index 339e7ac..e9fd121 100644 --- a/cmd/semTable.go +++ b/cmd/semTable.go @@ -2,66 +2,38 @@ package cmd import ( "fmt" - "github.com/anaskhan96/soup" ) -// semTable function - equivalent to your Python code func semTable(url string) { fmt.Println("Fetching semesters...") - res := fetchHTML(url) // Fetch the HTML content - - // Check if the response is empty - if res == "" { - fmt.Println("Failed to fetch the HTML content. Exiting.") - return - } - // Parse the HTML content using soup - doc := soup.HTMLParse(res) - div := doc.Find("div", "id", "aspect_artifactbrowser_CommunityViewer_div_community-view") + semesters, err := semTableReq(url) - if div.Error != nil { - fmt.Println("No semesters found on the page.") + if err != nil { + fmt.Errorf(err.Error()) return } - - ul := div.Find("ul") - li := ul.FindAll("li") - - if len(li) == 0 { - fmt.Println("No semesters found on the page.") - return - } - - // Display the found items + fmt.Printf("No\tSemesters\n") - for i, link := range li { - a := link.Find("a") - if a.Error == nil { - span := a.Find("span") - if span.Error == nil { - fmt.Printf("%d\t%s\n", i+1, span.Text()) // Extract the text from the span element - } - } + for i, semester := range semesters { + fmt.Printf("%d\t%s\n", i+1, semester.name) } - // Option to add "Back" - fmt.Printf("%d\tBack\n", len(li)+1) + // Option to add "Back". + fmt.Printf("%d\tBack\n", len(semesters)+1) - // append to stack stack.Push(url) - for { var ch int fmt.Print("\nEnter your semester: ") fmt.Scanln(&ch) - if ch > 0 && ch <= len(li) { - url := BASE_URL + li[ch-1].Find("a").Attrs()["href"] + if ch > 0 && ch <= len(semesters) { + url := BASE_URL + semesters[ch-1].path semChoose(url) break - } else if ch == len(li)+1 { + } else if ch == len(semesters)+1 { start() break } else { diff --git a/cmd/stack.go b/cmd/stack.go new file mode 100644 index 0000000..810484f --- /dev/null +++ b/cmd/stack.go @@ -0,0 +1,41 @@ +package cmd + +// Stack implementation using Go slices. +type Stack struct { + items []string +} + +// Push adds an item to the stack. +func (s *Stack) Push(item string) { + s.items = append(s.items, item) +} + +// Pop removes and returns the top item from the stack. +func (s *Stack) Pop() string { + if len(s.items) == 0 { + return "" + } + item := s.items[len(s.items)-1] + s.items = s.items[:len(s.items)-1] + return item +} + +// IsEmpty returns true if the stack is empty. +func (s *Stack) IsEmpty() bool { + return len(s.items) == 0 +} + +// Peek returns the top item without removing it. +func (s *Stack) Peek() string { + if len(s.items) == 0 { + return "" + } + return s.items[len(s.items)-1] +} + +// NewStack creates a new stack. +func NewStack() *Stack { + return &Stack{} +} + +var stack = NewStack() \ No newline at end of file diff --git a/cmd/year.go b/cmd/year.go index a627e38..bea6561 100644 --- a/cmd/year.go +++ b/cmd/year.go @@ -3,62 +3,37 @@ package cmd import ( "fmt" "os" - "github.com/anaskhan96/soup" ) - func year(url string) { fmt.Println("Fetching...") year_url := url - res := fetchHTML(url) - // Check if the response is empty - if res == "" { - fmt.Println("Failed to fetch the HTML content. Exiting.") + files, err := yearReq(url) + + if err != nil { + fmt.Errorf(err.Error()) return } - // Parse the HTML content using soup - doc := soup.HTMLParse(res) - div := doc.Find("div", "xmlns","http://di.tamu.edu/DRI/1.0/") - - ul := div.Find("ul") - li := ul.Find("li") - hyper := li.Find("a").Attrs()["href"] - - url = BASE_URL + hyper - page := fetchHTML(url) - - doc = soup.HTMLParse(page) - div = doc.Find("div", "class","file-list") - - subdiv := div.FindAll("div","class","file-wrapper") - - // Display the found items fmt.Printf("No\tFiles\n") - for i, item := range subdiv { - title := item.FindAll("div") - indiv := title[1].Find("div") - span := indiv.FindAll("span") - if span[0].Error == nil { - fmt.Printf("%d\t%s\n", i+1, span[1].Attrs()["title"]) // Extract the text from the span element - } + for i, file := range files { + fmt.Printf("%d\t%s\n", i+1, file.name) } - // Option to add "Back" - fmt.Printf("%d\tBack\n", len(subdiv)+1) + // Option to add "Back". + fmt.Printf("%d\tBack\n", len(files)+1) for { var ch int fmt.Print("\nEnter your choice: ") fmt.Scanln(&ch) - if ch > 0 && ch <= len(subdiv) { - title := subdiv[ch-1].FindAll("div") - link := title[0].Find("a").Attrs()["href"] + if ch > 0 && ch <= len(files) { + link := files[ch-1].path url = BASE_URL + link break - } else if ch == len(subdiv)+1 { + } else if ch == len(files)+1 { semChoose(stack.Pop()) } else { fmt.Println("Please enter a valid input!")