Skip to content

Commit

Permalink
feat(all/googledrive): Improve fetching of details (#2324)
Browse files Browse the repository at this point in the history
  • Loading branch information
Secozzi authored Oct 7, 2023
1 parent 38198c0 commit e00a845
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 22 deletions.
6 changes: 5 additions & 1 deletion src/all/googledrive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ Table of Content

## FAQ

### How do i add entries?
### How do I customize info?

The Google Drive Extension allow for editing the same way as [local anime](https://aniyomi.org/docs/guides/local-anime-source/advanced) .

### How do I add entries?
The Google Drive Extension *only* supports google drive folders, so no shared drives (but folders inside shared drives works fine!). If you have a folder, which contains sub-folders of an anime, such as:
```
https://drive.google.com/drive/folders/some-long-id
Expand Down
2 changes: 1 addition & 1 deletion src/all/googledrive/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ext {
extName = 'Google Drive'
pkgNameSuffix = 'all.googledrive'
extClass = '.GoogleDrive'
extVersionCode = 9
extVersionCode = 10
libVersion = '13'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import okhttp3.ProtocolException
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.internal.commonEmptyRequestBody
import org.jsoup.nodes.Document
import rx.Observable
import uy.kohesive.injekt.Injekt
Expand All @@ -45,7 +46,7 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {

override val id = 4222017068256633289

override var baseUrl = ""
override var baseUrl = "https://drive.google.com"

// Hack to manipulate what gets opened in webview
private val baseUrlInternal by lazy {
Expand Down Expand Up @@ -199,28 +200,55 @@ class GoogleDrive : ConfigurableAnimeSource, AnimeHttpSource() {
null
} ?: return Observable.just(anime)

if (driveDocument.selectFirst("title:contains(Error 404 \\(Not found\\))") != null) {
return Observable.just(anime)
}
// Get cover

var pageToken: String? = ""
while (pageToken != null) {
val response = client.newCall(
createPost(driveDocument, folderId),
).execute()
val coverResponse = client.newCall(
createPost(driveDocument, folderId, searchReqWithType(folderId, "cover", IMAGE_MIMETYPE)),
).execute().parseAs<PostResponse> { JSON_REGEX.find(it)!!.groupValues[1] }

val parsed = response.parseAs<PostResponse> {
JSON_REGEX.find(it)!!.groupValues[1]
}
coverResponse.items?.firstOrNull()?.let {
anime.thumbnail_url = "https://drive.google.com/uc?id=${it.id}"
}

if (parsed.items == null) throw Exception("Failed to load items, please log in through webview")
parsed.items.forEach {
if (it.mimeType.startsWith("image/") && it.title.startsWith("cover.")) {
anime.thumbnail_url = "https://drive.google.com/uc?id=${it.id}"
}
// Get details

val detailsResponse = client.newCall(
createPost(driveDocument, folderId, searchReqWithType(folderId, "details.json", "")),
).execute().parseAs<PostResponse> { JSON_REGEX.find(it)!!.groupValues[1] }

detailsResponse.items?.firstOrNull()?.let {
val newPostHeaders = getHeaders.newBuilder().apply {
add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
set("Host", "drive.usercontent.google.com")
add("Origin", "https://drive.google.com")
add("Referer", "https://drive.google.com/")
add("X-Drive-First-Party", "DriveWebUi")
add("X-Json-Requested", "true")
}.build()

val newPostUrl = "https://drive.usercontent.google.com/uc?id=${it.id}&authuser=0&export=download"

val newResponse = client.newCall(
POST(newPostUrl, headers = newPostHeaders, body = commonEmptyRequestBody),
).execute().parseAs<DownloadResponse> { JSON_REGEX.find(it)!!.groupValues[1] }

val downloadHeaders = headers.newBuilder().apply {
add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
add("Connection", "keep-alive")
add("Cookie", getCookie("https://drive.usercontent.google.com"))
add("Host", "drive.usercontent.google.com")
}.build()

client.newCall(
GET(newResponse.downloadUrl, headers = downloadHeaders),
).execute().parseAs<DetailsJson>().let { t ->
t.title?.let { anime.title = it }
t.author?.let { anime.author = it }
t.artist?.let { anime.artist = it }
t.description?.let { anime.description = it }
t.genre?.let { anime.genre = it.joinToString(", ") }
t.status?.let { anime.status = it.toIntOrNull() ?: SAnime.UNKNOWN }
}

pageToken = parsed.nextPageToken
}

return Observable.just(anime)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,18 @@ data class LinkDataInfo(
val title: String,
val size: String,
)

@Serializable
data class DownloadResponse(
val downloadUrl: String,
)

@Serializable
data class DetailsJson(
val title: String? = null,
val author: String? = null,
val artist: String? = null,
val description: String? = null,
val genre: List<String>? = null,
val status: String? = null,
)
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package eu.kanade.tachiyomi.animeextension.all.googledrive

fun searchReq(parentId: String, query: String): (String, String, String) -> String {
return searchReqWithType(parentId, query, type = FOLDER_MIMETYPE)
}

fun searchReqWithType(parentId: String, query: String, type: String): (String, String, String) -> String {
return { _: String, nextPageToken: String, key: String ->
"/drive/v2internal/files?openDrive=false&reason=111&syncType=0&errorRecovery=false&q=title%20contains%20'$query'%20and%20(mimeType%20in%20'application%2Fvnd.google-apps.folder'%20or%20shortcutDetails.targetMimeType%20in%20'application%2Fvnd.google-apps.folder')%20and%20trashed%20%3D%20false%20and%20'$parentId'%20in%20ancestors&fields=kind%2CnextPageToken%2Citems(kind%2CmodifiedDate%2ChasVisitorPermissions%2CcontainsUnsubscribedChildren%2CmodifiedByMeDate%2ClastViewedByMeDate%2CalternateLink%2CfileSize%2Cowners(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2ClastModifyingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CcustomerId%2CancestorHasAugmentedPermissions%2ChasThumbnail%2CthumbnailVersion%2Ctitle%2Cid%2CresourceKey%2CabuseIsAppealable%2CabuseNoticeReason%2Cshared%2CaccessRequestsCount%2CsharedWithMeDate%2CuserPermission(role)%2CexplicitlyTrashed%2CmimeType%2CquotaBytesUsed%2Ccopyable%2Csubscribed%2CfolderColor%2ChasChildFolders%2CfileExtension%2CprimarySyncParentId%2CsharingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CflaggedForAbuse%2CfolderFeatures%2Cspaces%2CsourceAppId%2Crecency%2CrecencyReason%2Cversion%2CactionItems%2CteamDriveId%2ChasAugmentedPermissions%2CcreatedDate%2CprimaryDomainName%2CorganizationDisplayName%2CpassivelySubscribed%2CtrashingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CtrashedDate%2Cparents(id)%2Ccapabilities(canMoveItemIntoTeamDrive%2CcanUntrash%2CcanModifyContentRestriction%2CcanMoveItemWithinTeamDrive%2CcanMoveItemOutOfTeamDrive%2CcanDeleteChildren%2CcanTrashChildren%2CcanRequestApproval%2CcanReadCategoryMetadata%2CcanEditCategoryMetadata%2CcanAddMyDriveParent%2CcanRemoveMyDriveParent%2CcanShareChildFiles%2CcanShareChildFolders%2CcanRead%2CcanMoveItemWithinDrive%2CcanMoveChildrenWithinDrive%2CcanAddFolderFromAnotherDrive%2CcanChangeSecurityUpdateEnabled%2CcanBlockOwner%2CcanReportSpamOrAbuse%2CcanCopy%2CcanDownload%2CcanEdit%2CcanAddChildren%2CcanDelete%2CcanRemoveChildren%2CcanShare%2CcanTrash%2CcanRename%2CcanReadTeamDrive%2CcanMoveTeamDriveItem)%2CcontentRestrictions(readOnly)%2CapprovalMetadata(approvalVersion%2CapprovalSummaries%2ChasIncomingApproval)%2CshortcutDetails(targetId%2CtargetMimeType%2CtargetLookupStatus%2CtargetFile%2CcanRequestAccessToTarget)%2CspamMetadata(markedAsSpamDate%2CinSpamView)%2Clabels(starred%2Ctrashed%2Crestricted%2Cviewed))%2CincompleteSearch&appDataFilter=NO_APP_DATA&spaces=drive&pageToken=$nextPageToken&maxResults=50&rawUserQuery=parent%3A$parentId%20type%3Afolder%20title%3A$query&supportsTeamDrives=true&includeItemsFromAllDrives=true&corpora=default&orderBy=relevance%20desc&retryCount=0&key=$key HTTP/1.1"
"/drive/v2internal/files?openDrive=false&reason=111&syncType=0&errorRecovery=false&q=title%20contains%20'$query'$type%20and%20trashed%20%3D%20false%20and%20'$parentId'%20in%20ancestors&fields=kind%2CnextPageToken%2Citems(kind%2CmodifiedDate%2ChasVisitorPermissions%2CcontainsUnsubscribedChildren%2CmodifiedByMeDate%2ClastViewedByMeDate%2CalternateLink%2CfileSize%2Cowners(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2ClastModifyingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CcustomerId%2CancestorHasAugmentedPermissions%2ChasThumbnail%2CthumbnailVersion%2Ctitle%2Cid%2CresourceKey%2CabuseIsAppealable%2CabuseNoticeReason%2Cshared%2CaccessRequestsCount%2CsharedWithMeDate%2CuserPermission(role)%2CexplicitlyTrashed%2CmimeType%2CquotaBytesUsed%2Ccopyable%2Csubscribed%2CfolderColor%2ChasChildFolders%2CfileExtension%2CprimarySyncParentId%2CsharingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CflaggedForAbuse%2CfolderFeatures%2Cspaces%2CsourceAppId%2Crecency%2CrecencyReason%2Cversion%2CactionItems%2CteamDriveId%2ChasAugmentedPermissions%2CcreatedDate%2CprimaryDomainName%2CorganizationDisplayName%2CpassivelySubscribed%2CtrashingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CtrashedDate%2Cparents(id)%2Ccapabilities(canMoveItemIntoTeamDrive%2CcanUntrash%2CcanModifyContentRestriction%2CcanMoveItemWithinTeamDrive%2CcanMoveItemOutOfTeamDrive%2CcanDeleteChildren%2CcanTrashChildren%2CcanRequestApproval%2CcanReadCategoryMetadata%2CcanEditCategoryMetadata%2CcanAddMyDriveParent%2CcanRemoveMyDriveParent%2CcanShareChildFiles%2CcanShareChildFolders%2CcanRead%2CcanMoveItemWithinDrive%2CcanMoveChildrenWithinDrive%2CcanAddFolderFromAnotherDrive%2CcanChangeSecurityUpdateEnabled%2CcanBlockOwner%2CcanReportSpamOrAbuse%2CcanCopy%2CcanDownload%2CcanEdit%2CcanAddChildren%2CcanDelete%2CcanRemoveChildren%2CcanShare%2CcanTrash%2CcanRename%2CcanReadTeamDrive%2CcanMoveTeamDriveItem)%2CcontentRestrictions(readOnly)%2CapprovalMetadata(approvalVersion%2CapprovalSummaries%2ChasIncomingApproval)%2CshortcutDetails(targetId%2CtargetMimeType%2CtargetLookupStatus%2CtargetFile%2CcanRequestAccessToTarget)%2CspamMetadata(markedAsSpamDate%2CinSpamView)%2Clabels(starred%2Ctrashed%2Crestricted%2Cviewed))%2CincompleteSearch&appDataFilter=NO_APP_DATA&spaces=drive&pageToken=$nextPageToken&maxResults=50&rawUserQuery=parent%3A$parentId%20type%3Afolder%20title%3A$query&supportsTeamDrives=true&includeItemsFromAllDrives=true&corpora=default&orderBy=relevance%20desc&retryCount=0&key=$key HTTP/1.1"
}
}

fun defaultGetRequest(folderId: String, nextPageToken: String, key: String): String {
return "/drive/v2internal/files?openDrive=false&reason=102&syncType=0&errorRecovery=false&q=trashed%20%3D%20false%20and%20'$folderId'%20in%20parents&fields=kind%2CnextPageToken%2Citems(kind%2CmodifiedDate%2ChasVisitorPermissions%2CcontainsUnsubscribedChildren%2CmodifiedByMeDate%2ClastViewedByMeDate%2CalternateLink%2CfileSize%2Cowners(kind%2CpermissionId%2CemailAddressFromAccount%2Cdomain%2Cid)%2ClastModifyingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CcustomerId%2CancestorHasAugmentedPermissions%2ChasThumbnail%2CthumbnailVersion%2Ctitle%2Cid%2CresourceKey%2CabuseIsAppealable%2CabuseNoticeReason%2Cshared%2CaccessRequestsCount%2CsharedWithMeDate%2CuserPermission(role)%2CexplicitlyTrashed%2CmimeType%2CquotaBytesUsed%2Ccopyable%2Csubscribed%2CfolderColor%2ChasChildFolders%2CfileExtension%2CprimarySyncParentId%2CsharingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CflaggedForAbuse%2CfolderFeatures%2Cspaces%2CsourceAppId%2Crecency%2CrecencyReason%2Cversion%2CactionItems%2CteamDriveId%2ChasAugmentedPermissions%2CcreatedDate%2CprimaryDomainName%2CorganizationDisplayName%2CpassivelySubscribed%2CtrashingUser(kind%2CpermissionId%2CemailAddressFromAccount%2Cid)%2CtrashedDate%2Cparents(id)%2Ccapabilities(canMoveItemIntoTeamDrive%2CcanUntrash%2CcanMoveItemWithinTeamDrive%2CcanMoveItemOutOfTeamDrive%2CcanDeleteChildren%2CcanTrashChildren%2CcanRequestApproval%2CcanReadCategoryMetadata%2CcanEditCategoryMetadata%2CcanAddMyDriveParent%2CcanRemoveMyDriveParent%2CcanShareChildFiles%2CcanShareChildFolders%2CcanRead%2CcanMoveItemWithinDrive%2CcanMoveChildrenWithinDrive%2CcanAddFolderFromAnotherDrive%2CcanChangeSecurityUpdateEnabled%2CcanBlockOwner%2CcanReportSpamOrAbuse%2CcanCopy%2CcanDownload%2CcanEdit%2CcanAddChildren%2CcanDelete%2CcanRemoveChildren%2CcanShare%2CcanTrash%2CcanRename%2CcanReadTeamDrive%2CcanMoveTeamDriveItem)%2CcontentRestrictions(readOnly)%2CapprovalMetadata(approvalVersion%2CapprovalSummaries%2ChasIncomingApproval)%2CshortcutDetails(targetId%2CtargetMimeType%2CtargetLookupStatus%2CtargetFile%2CcanRequestAccessToTarget)%2CspamMetadata(markedAsSpamDate%2CinSpamView)%2Clabels(starred%2Ctrashed%2Crestricted%2Cviewed))%2CincompleteSearch&appDataFilter=NO_APP_DATA&spaces=drive&pageToken=$nextPageToken&maxResults=100&supportsTeamDrives=true&includeItemsFromAllDrives=true&corpora=default&orderBy=folder%2Ctitle_natural%20asc&retryCount=0&key=$key HTTP/1.1"
}

const val IMAGE_MIMETYPE = "%20and%20(mimeType%20in%20'image%2Fbmp'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fbmp%22'%2C%20'image%2Fjpeg'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fjpeg%22'%2C%20'image%2Fpng'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fpng%22'%2C%20'image%2Fgif'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fgif%22'%2C%20'image%2Ftiff'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Ftiff%22'%2C%20'image%2Fx-ms-bmp'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fx-ms-bmp%22'%2C%20'image%2Fsvg%2Bxml'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fsvg%2Bxml%22'%2C%20'image%2Fvnd.microsoft.icon'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fvnd.microsoft.icon%22'%2C%20'image%2Fheif'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fheif%22'%2C%20'image%2Fheic'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fheic%22'%2C%20'image%2Fwebp'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fwebp%22'%20or%20shortcutDetails.targetMimeType%20in%20'image%2Fbmp'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fbmp%22'%2C%20'image%2Fjpeg'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fjpeg%22'%2C%20'image%2Fpng'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fpng%22'%2C%20'image%2Fgif'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fgif%22'%2C%20'image%2Ftiff'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Ftiff%22'%2C%20'image%2Fx-ms-bmp'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fx-ms-bmp%22'%2C%20'image%2Fsvg%2Bxml'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fsvg%2Bxml%22'%2C%20'image%2Fvnd.microsoft.icon'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fvnd.microsoft.icon%22'%2C%20'image%2Fheif'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fheif%22'%2C%20'image%2Fheic'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fheic%22'%2C%20'image%2Fwebp'%2C%20'application%2Fvnd.google-gsuite.encrypted%3B%20content%3D%22image%2Fwebp%22')"
const val FOLDER_MIMETYPE = "%20and%20(mimeType%20in%20'application%2Fvnd.google-apps.folder'%20or%20shortcutDetails.targetMimeType%20in%20'application%2Fvnd.google-apps.folder')"

0 comments on commit e00a845

Please sign in to comment.