Archived
PARSING HTML WORKS AND IT GETS SAVED TO THE DATABASE WOOO
This commit is contained in:
@@ -26,7 +26,7 @@ class StudIPEventAdapter(private val events: List<StudIPEvent>) : RecyclerView.A
|
|||||||
holder.binding.textTitle.text = currentItem.title
|
holder.binding.textTitle.text = currentItem.title
|
||||||
holder.binding.textLecturers.text = currentItem.lecturer
|
holder.binding.textLecturers.text = currentItem.lecturer
|
||||||
holder.binding.textRoom.text = currentItem.room
|
holder.binding.textRoom.text = currentItem.room
|
||||||
holder.binding.textTimeslot.text = currentItem.timeslot
|
holder.binding.textTimeslot.text = currentItem.timeslot()
|
||||||
|
|
||||||
// TODO inflate view saying "no events!" or sth
|
// TODO inflate view saying "no events!" or sth
|
||||||
|
|
||||||
|
|||||||
@@ -13,4 +13,45 @@ object DummyData {
|
|||||||
StudIPEvent(6, "Gesellschaft und Raum", "Lossau, Mossig", "GW2 B1820", 3, 1, 1),
|
StudIPEvent(6, "Gesellschaft und Raum", "Lossau, Mossig", "GW2 B1820", 3, 1, 1),
|
||||||
StudIPEvent(7, "Gesellschaft und Raum2", "Lossau, Mossig", "GW2 B1820", 4, 4, 2),
|
StudIPEvent(7, "Gesellschaft und Raum2", "Lossau, Mossig", "GW2 B1820", 4, 4, 2),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val timeslotStartMap: Map<String, Int> = mapOf(
|
||||||
|
"6:00" to 0,
|
||||||
|
"6:15" to 0,
|
||||||
|
"8:00" to 1,
|
||||||
|
"8:15" to 1,
|
||||||
|
"10:00" to 2,
|
||||||
|
"10:15" to 2,
|
||||||
|
"12:00" to 3,
|
||||||
|
"12:15" to 3,
|
||||||
|
"14:00" to 4,
|
||||||
|
"14:15" to 4,
|
||||||
|
"16:00" to 5,
|
||||||
|
"16:15" to 5,
|
||||||
|
"18:00" to 6,
|
||||||
|
"18:15" to 6,
|
||||||
|
)
|
||||||
|
|
||||||
|
val timeslotEndMap: Map<String, Int> = mapOf(
|
||||||
|
"8:00" to 0,
|
||||||
|
"7:45" to 0,
|
||||||
|
"10:00" to 1,
|
||||||
|
"9:45" to 1,
|
||||||
|
"12:00" to 2,
|
||||||
|
"11:45" to 2,
|
||||||
|
"14:00" to 3,
|
||||||
|
"13:45" to 3,
|
||||||
|
"16:00" to 4,
|
||||||
|
"15:45" to 4,
|
||||||
|
"18:00" to 5,
|
||||||
|
"17:45" to 5,
|
||||||
|
"20:00" to 6,
|
||||||
|
"19:45" to 6,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun parseTimeslot(time: String): Pair<Int, Int> {
|
||||||
|
val splitTime = time.split(" - ")
|
||||||
|
val start = timeslotStartMap[splitTime[0]] ?: 0
|
||||||
|
val length = (timeslotEndMap[splitTime[1]] ?: 0)
|
||||||
|
return Pair(start, length)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.denizk0461.studip.data
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.denizk0461.studip.model.StudIPEvent
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
|
class StudIPParser {
|
||||||
|
|
||||||
|
fun parse(html: String, insert: (events: List<StudIPEvent>) -> Unit) {
|
||||||
|
var id = 0
|
||||||
|
val doc = Jsoup.parse(html)
|
||||||
|
Log.d("HELLO2", "doc: $doc")
|
||||||
|
val newEvents = mutableListOf<StudIPEvent>()
|
||||||
|
val columns = arrayOf(
|
||||||
|
doc.getElementById("calendar_view_1_column_0"),
|
||||||
|
doc.getElementById("calendar_view_1_column_1"),
|
||||||
|
doc.getElementById("calendar_view_1_column_2"),
|
||||||
|
doc.getElementById("calendar_view_1_column_3"),
|
||||||
|
doc.getElementById("calendar_view_1_column_4"),
|
||||||
|
)
|
||||||
|
Log.d("HELLO2", "days found: ${columns.size}, element 1: ${columns[0]}")
|
||||||
|
columns.forEachIndexed { index, element ->
|
||||||
|
element?.getElementsByClass("schedule_entry")?.forEachIndexed { entryIndex, entry ->
|
||||||
|
Log.d("HELLO2", "element - $entryIndex - found: $entry")
|
||||||
|
val entryHeader = entry.getElementsByTag("dt")[0].text()
|
||||||
|
val delimiter = entryHeader.lastIndexOf('(')
|
||||||
|
val parsedTitle = entryHeader.substring(0 until delimiter)
|
||||||
|
val parsedLecturers = entryHeader.substring(delimiter + 1 until entryHeader.length - 1)
|
||||||
|
|
||||||
|
val entryInfos = entry.getElementsByTag("dd")[0].text().split(", ")
|
||||||
|
val timeSlot = DummyData.parseTimeslot(entryInfos[0])
|
||||||
|
|
||||||
|
val event = StudIPEvent(
|
||||||
|
id = id,
|
||||||
|
title = parsedTitle,
|
||||||
|
lecturer = parsedLecturers,
|
||||||
|
room = entryInfos[1],
|
||||||
|
day = index,
|
||||||
|
timeslotStart = timeSlot.first,
|
||||||
|
timeslotEnd = timeSlot.second,
|
||||||
|
)
|
||||||
|
newEvents.add(event)
|
||||||
|
id += 1
|
||||||
|
Log.d("HELLO2", event.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insert(newEvents)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.denizk0461.studip.data
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
|
|
||||||
class StudIPScraper : WebViewClient() {
|
|
||||||
|
|
||||||
fun parse(context: Context) {
|
|
||||||
|
|
||||||
// val res = Jsoup.connect("https://elearning.uni-bremen.de/index.php?again=yes")
|
|
||||||
// .data("loginname", "deniz7", "password", "xSh4d0wZ3r0_+nbrmn")
|
|
||||||
// .method(Connection.Method.POST)
|
|
||||||
// .execute()
|
|
||||||
// val doc = Jsoup.connect("https://elearning.uni-bremen.de/dispatch.php/calendar/schedule").get()
|
|
||||||
// Log.d("HELLO", doc.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
|
|
||||||
super.onPageStarted(view, url, favicon)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPageFinished(view: WebView?, url: String?) {
|
|
||||||
super.onPageFinished(view, url)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,9 @@ interface EventDAO {
|
|||||||
@Insert
|
@Insert
|
||||||
fun insertEvent(event: StudIPEvent)
|
fun insertEvent(event: StudIPEvent)
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insertEvents(event: List<StudIPEvent>)
|
||||||
|
|
||||||
@Query("DELETE FROM events")
|
@Query("DELETE FROM events")
|
||||||
fun nukeEvents()
|
fun nukeEvents()
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ import androidx.room.Room
|
|||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import com.denizk0461.studip.model.StudIPEvent
|
import com.denizk0461.studip.model.StudIPEvent
|
||||||
|
|
||||||
@Database(entities = [StudIPEvent::class], version = 1)
|
@Database(entities = [StudIPEvent::class], version = 2)
|
||||||
abstract class EventDatabase : RoomDatabase() {
|
abstract class EventDatabase : RoomDatabase() {
|
||||||
|
|
||||||
abstract fun dao(): EventDAO
|
abstract fun dao(): EventDAO
|
||||||
@@ -21,7 +21,7 @@ abstract class EventDatabase : RoomDatabase() {
|
|||||||
context.applicationContext,
|
context.applicationContext,
|
||||||
EventDatabase::class.java,
|
EventDatabase::class.java,
|
||||||
"event_db"
|
"event_db"
|
||||||
).build()
|
).fallbackToDestructiveMigration().build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return instance!!
|
return instance!!
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ class EventRepository(app: Application) {
|
|||||||
|
|
||||||
fun nukeEvents() { dao.nukeEvents() }
|
fun nukeEvents() { dao.nukeEvents() }
|
||||||
fun insertEvent(event: StudIPEvent) { dao.insertEvent(event) }
|
fun insertEvent(event: StudIPEvent) { dao.insertEvent(event) }
|
||||||
|
fun insertEvents(events: List<StudIPEvent>) { dao.insertEvents(events) }
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ import androidx.recyclerview.widget.PagerSnapHelper
|
|||||||
import com.denizk0461.studip.R
|
import com.denizk0461.studip.R
|
||||||
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
|
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
|
||||||
import com.denizk0461.studip.data.DummyData
|
import com.denizk0461.studip.data.DummyData
|
||||||
import com.denizk0461.studip.data.StudIPScraper
|
import com.denizk0461.studip.data.StudIPParser
|
||||||
import com.denizk0461.studip.databinding.FragmentEventBinding
|
import com.denizk0461.studip.databinding.FragmentEventBinding
|
||||||
import com.denizk0461.studip.viewmodel.EventViewModel
|
import com.denizk0461.studip.viewmodel.EventViewModel
|
||||||
|
|
||||||
@@ -40,16 +40,17 @@ class EventFragment : Fragment() {
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
viewModel.allEvents.observe(viewLifecycleOwner) { events ->
|
viewModel.allEvents.observe(viewLifecycleOwner) { events ->
|
||||||
recyclerViewAdapter = StudIPEventPageAdapter(DummyData.events.toList())
|
recyclerViewAdapter = StudIPEventPageAdapter(events)//DummyData.events.toList())
|
||||||
binding.recyclerView.adapter = recyclerViewAdapter
|
binding.recyclerView.adapter = recyclerViewAdapter
|
||||||
recyclerViewLayoutManager =
|
recyclerViewLayoutManager =
|
||||||
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
binding.recyclerView.layoutManager = recyclerViewLayoutManager
|
binding.recyclerView.layoutManager = recyclerViewLayoutManager
|
||||||
|
binding.recyclerView.onFlingListener = null
|
||||||
PagerSnapHelper().attachToRecyclerView(binding.recyclerView)
|
PagerSnapHelper().attachToRecyclerView(binding.recyclerView)
|
||||||
binding.recyclerView.scheduleLayoutAnimation()
|
binding.recyclerView.scheduleLayoutAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.doAsync { StudIPScraper().parse(requireContext()) }
|
// viewModel.doAsync { StudIPParser().parse(requireContext()) }
|
||||||
|
|
||||||
binding.fab.setOnClickListener { view ->
|
binding.fab.setOnClickListener { view ->
|
||||||
launchWebview()
|
launchWebview()
|
||||||
|
|||||||
+28
-12
@@ -1,31 +1,33 @@
|
|||||||
package com.denizk0461.studip.fragment
|
package com.denizk0461.studip.fragment
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.webkit.ValueCallback
|
|
||||||
import android.webkit.WebChromeClient
|
|
||||||
import android.webkit.WebResourceRequest
|
import android.webkit.WebResourceRequest
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.fragment.app.Fragment
|
||||||
import com.denizk0461.studip.R
|
import androidx.fragment.app.viewModels
|
||||||
|
import com.denizk0461.studip.data.StudIPParser
|
||||||
import com.denizk0461.studip.databinding.FragmentSecondBinding
|
import com.denizk0461.studip.databinding.FragmentSecondBinding
|
||||||
|
import com.denizk0461.studip.viewmodel.ParserViewModel
|
||||||
|
import java.net.URLDecoder
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple [Fragment] subclass as the second destination in the navigation.
|
* A simple [Fragment] subclass as the second destination in the navigation.
|
||||||
*/
|
*/
|
||||||
class SecondFragment : Fragment() {
|
class ParserFragment : Fragment() {
|
||||||
|
|
||||||
private var _binding: FragmentSecondBinding? = null
|
private var _binding: FragmentSecondBinding? = null
|
||||||
|
private var html = "" // temporary storage for the website HTML
|
||||||
|
|
||||||
// This property is only valid between onCreateView and
|
// This property is only valid between onCreateView and
|
||||||
// onDestroyView.
|
// onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private val viewModel: ParserViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
@@ -43,24 +45,38 @@ class SecondFragment : Fragment() {
|
|||||||
// findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
|
// findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
binding.webview.settings.javaScriptEnabled = true
|
binding.webview.settings.apply {
|
||||||
|
javaScriptEnabled = true
|
||||||
|
}
|
||||||
binding.webview.webViewClient = object : WebViewClient() {
|
binding.webview.webViewClient = object : WebViewClient() {
|
||||||
override fun shouldOverrideUrlLoading(
|
override fun shouldOverrideUrlLoading(
|
||||||
view: WebView?,
|
view: WebView,
|
||||||
request: WebResourceRequest?
|
request: WebResourceRequest
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
override fun onPageFinished(view: WebView, url: String) {
|
||||||
|
binding.webview.loadUrl(
|
||||||
|
"javascript:window.HtmlViewer.showHTML" +
|
||||||
|
"('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.webview.loadUrl("https://elearning.uni-bremen.de/index.php?again=yes")
|
binding.webview.loadUrl("https://elearning.uni-bremen.de/index.php?again=yes")
|
||||||
|
|
||||||
binding.fab.setOnClickListener { view ->
|
binding.fab.setOnClickListener { view ->
|
||||||
binding.webview.evaluateJavascript(
|
binding.webview.evaluateJavascript(
|
||||||
"(function(){return window.document.body.outerHTML})();"
|
"(function(){return encodeURI(document.getElementsByTagName('html')[0].innerHTML)})();"
|
||||||
) { p0 ->
|
) { p0 ->
|
||||||
Log.d("HELLO", p0 ?: "nothing returned")
|
viewModel.nukeEvents()
|
||||||
|
StudIPParser().parse(URLDecoder.decode(p0, "UTF-8")) { events ->
|
||||||
|
viewModel.insertEvents(events)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// html.chunked(3000).forEach {
|
||||||
|
// Log.d("HELLO", it)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.denizk0461.studip.model
|
package com.denizk0461.studip.model
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.Ignore
|
import androidx.room.Ignore
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
@@ -11,15 +12,26 @@ data class StudIPEvent(
|
|||||||
val lecturer: String, // the lecturer(s)
|
val lecturer: String, // the lecturer(s)
|
||||||
val room: String, // the room the event takes place in
|
val room: String, // the room the event takes place in
|
||||||
val day: Int, // 0 = Monday, 1 = Tuesday, 2 = Wednesday, 3 = Thursday, 4 = Friday
|
val day: Int, // 0 = Monday, 1 = Tuesday, 2 = Wednesday, 3 = Thursday, 4 = Friday
|
||||||
val timeslotStart: Int, // 0 = 08:15, 1 = 10:15, 2 = 12:15, 3 = 14:15, 4 = 16:15, 5 = 18:15
|
val timeslotStart: Int, // 1 = 08:15, 2 = 10:15, 3 = 12:15, 4 = 14:15, 5 = 16:15, 6 = 18:15
|
||||||
val timeslots: Int, // the amount of timeslots the course takes place over (1 timeslot = 90min)
|
val timeslotEnd: Int, // 1 = 09:45 etc.
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@Ignore private val timeSlotStartTimes: List<String> = listOf("08:15", "10:15", "12:15", "14:15", "16:15", "18:15")
|
// constructor(
|
||||||
@Ignore private val timeSlotEndTimes: List<String> = listOf("09:45", "11:45", "13:45", "15:45", "17:45", "19:45")
|
// val title: String,
|
||||||
|
// val lecturer: String,
|
||||||
|
// val room: String,
|
||||||
|
// val day: Int,
|
||||||
|
// val
|
||||||
|
// ) : this(title, lecturer, room, day, 1, 1)
|
||||||
|
|
||||||
@Ignore val timeslot: String =
|
@Ignore private val timeSlotStartTimes: List<String> = listOf("06:15", "08:15", "10:15", "12:15", "14:15", "16:15", "18:15")
|
||||||
"${timeSlotStartTimes[timeslotStart]} – ${timeSlotEndTimes[timeslotStart + timeslots - 1]}"
|
@Ignore private val timeSlotEndTimes: List<String> = listOf("07:45", "09:45", "11:45", "13:45", "15:45", "17:45", "19:45")
|
||||||
|
|
||||||
|
fun timeslot(): String {
|
||||||
|
Log.d("HELLO3", title)
|
||||||
|
Log.d("HELLO3", "s $timeslotStart st $timeslotEnd")
|
||||||
|
return "${timeSlotStartTimes[timeslotStart]} – ${timeSlotEndTimes[timeslotEnd]}"
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
@@ -32,7 +44,6 @@ data class StudIPEvent(
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = id
|
var result = id
|
||||||
result = 31 * result + title.hashCode()
|
result = 31 * result + title.hashCode()
|
||||||
@@ -40,10 +51,9 @@ data class StudIPEvent(
|
|||||||
result = 31 * result + room.hashCode()
|
result = 31 * result + room.hashCode()
|
||||||
result = 31 * result + day
|
result = 31 * result + day
|
||||||
result = 31 * result + timeslotStart
|
result = 31 * result + timeslotStart
|
||||||
result = 31 * result + timeslots
|
result = 31 * result + timeslotEnd
|
||||||
result = 31 * result + timeSlotStartTimes.hashCode()
|
result = 31 * result + timeSlotStartTimes.hashCode()
|
||||||
result = 31 * result + timeSlotEndTimes.hashCode()
|
result = 31 * result + timeSlotEndTimes.hashCode()
|
||||||
result = 31 * result + timeslot.hashCode()
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.denizk0461.studip.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import com.denizk0461.studip.model.StudIPEvent
|
||||||
|
|
||||||
|
class ParserViewModel(app: Application) : TemplateViewModel(app) {
|
||||||
|
|
||||||
|
fun insertEvent(event: StudIPEvent) { repo.insertEvent(event) }
|
||||||
|
fun insertEvents(events: List<StudIPEvent>) { doAsync { repo.insertEvents(events) } }
|
||||||
|
fun nukeEvents() { doAsync { repo.nukeEvents() } }
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".fragment.SecondFragment">
|
tools:context=".fragment.ParserFragment">
|
||||||
|
|
||||||
<WebView
|
<WebView
|
||||||
android:id="@+id/webview"
|
android:id="@+id/webview"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/SecondFragment"
|
android:id="@+id/SecondFragment"
|
||||||
android:name="com.denizk0461.studip.fragment.SecondFragment"
|
android:name="com.denizk0461.studip.fragment.ParserFragment"
|
||||||
android:label="@string/second_fragment_label"
|
android:label="@string/second_fragment_label"
|
||||||
tools:layout="@layout/fragment_second">
|
tools:layout="@layout/fragment_second">
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user