package mediafire /* Package mediafire Author: Da3zKi7 Date: 2025-09-11 D@' 3z K!7 - The King Of Cracking */ import ( "context" "fmt" "net/http" "os" "time" "github.com/OpenListTeam/OpenList/v4/drivers/base" "github.com/OpenListTeam/OpenList/v4/internal/driver" "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/pkg/utils" ) type Mediafire struct { model.Storage Addition actionToken string appBase string apiBase string hostBase string maxRetries int secChUa string secChUaPlatform string userAgent string } func (d *Mediafire) Config() driver.Config { return config } func (d *Mediafire) GetAddition() driver.Additional { return &d.Addition } func (d *Mediafire) Init(ctx context.Context) error { if d.SessionToken == "" { return fmt.Errorf("Init :: [MediaFire] {critical} missing sessionToken") } if d.Cookie == "" { return fmt.Errorf("Init :: [MediaFire] {critical} missing Cookie") } if _, err := d.getSessionToken(ctx); err != nil { //fmt.Printf("Init :: Obtain Session Token \n\n") if err := d.renewToken(ctx); err != nil { //fmt.Printf("Init :: Renew Session Token \n\n") } } return nil } func (d *Mediafire) Drop(ctx context.Context) error { return nil } func (d *Mediafire) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { files, err := d.getFiles(ctx, dir.GetID()) if err != nil { return nil, err } return utils.SliceConvert(files, func(src File) (model.Obj, error) { return d.fileToObj(src), nil }) } func (d *Mediafire) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { downloadUrl, err := d.getDirectDownloadLink(ctx, file.GetID()) if err != nil { return nil, err } res, err := base.NoRedirectClient.R().SetDoNotParseResponse(true).SetContext(ctx).Get(downloadUrl) if err != nil { return nil, err } defer func() { _ = res.RawBody().Close() }() if res.StatusCode() == 302 { downloadUrl = res.Header().Get("location") } return &model.Link{ URL: downloadUrl, Header: http.Header{ "Origin": []string{d.appBase}, "Referer": []string{d.appBase + "/"}, "sec-ch-ua": []string{d.secChUa}, "sec-ch-ua-platform": []string{d.secChUaPlatform}, "User-Agent": []string{d.userAgent}, //"User-Agent": []string{base.UserAgent}, }, }, nil } func (d *Mediafire) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) { data := map[string]string{ "session_token": d.SessionToken, "response_format": "json", "parent_key": parentDir.GetID(), "foldername": dirName, } var resp MediafireFolderCreateResponse _, err := d.postForm("/folder/create.php", data, &resp) if err != nil { return nil, err } if resp.Response.Result != "Success" { return nil, fmt.Errorf("MediaFire API error: %s", resp.Response.Result) } created, _ := time.Parse("2006-01-02T15:04:05Z", resp.Response.CreatedUTC) return &model.ObjThumb{ Object: model.Object{ ID: resp.Response.FolderKey, Name: resp.Response.Name, Size: 0, Modified: created, Ctime: created, IsFolder: true, }, Thumbnail: model.Thumbnail{}, }, nil } func (d *Mediafire) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) { var data map[string]string var endpoint string if srcObj.IsDir() { endpoint = "/folder/move.php" data = map[string]string{ "session_token": d.SessionToken, "response_format": "json", "folder_key_src": srcObj.GetID(), "folder_key_dst": dstDir.GetID(), } } else { endpoint = "/file/move.php" data = map[string]string{ "session_token": d.SessionToken, "response_format": "json", "quick_key": srcObj.GetID(), "folder_key": dstDir.GetID(), } } var resp MediafireMoveResponse _, err := d.postForm(endpoint, data, &resp) if err != nil { return nil, err } if resp.Response.Result != "Success" { return nil, fmt.Errorf("MediaFire API error: %s", resp.Response.Result) } return srcObj, nil } func (d *Mediafire) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) { var data map[string]string var endpoint string if srcObj.IsDir() { endpoint = "/folder/update.php" data = map[string]string{ "session_token": d.SessionToken, "response_format": "json", "folder_key": srcObj.GetID(), "foldername": newName, } } else { endpoint = "/file/update.php" data = map[string]string{ "session_token": d.SessionToken, "response_format": "json", "quick_key": srcObj.GetID(), "filename": newName, } } var resp MediafireRenameResponse _, err := d.postForm(endpoint, data, &resp) if err != nil { return nil, err } if resp.Response.Result != "Success" { return nil, fmt.Errorf("MediaFire API error: %s", resp.Response.Result) } return &model.ObjThumb{ Object: model.Object{ ID: srcObj.GetID(), Name: newName, Size: srcObj.GetSize(), Modified: srcObj.ModTime(), Ctime: srcObj.CreateTime(), IsFolder: srcObj.IsDir(), }, Thumbnail: model.Thumbnail{}, }, nil } func (d *Mediafire) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) { var data map[string]string var endpoint string if srcObj.IsDir() { endpoint = "/folder/copy.php" data = map[string]string{ "session_token": d.SessionToken, "response_format": "json", "folder_key_src": srcObj.GetID(), "folder_key_dst": dstDir.GetID(), } } else { endpoint = "/file/copy.php" data = map[string]string{ "session_token": d.SessionToken, "response_format": "json", "quick_key": srcObj.GetID(), "folder_key": dstDir.GetID(), } } var resp MediafireCopyResponse _, err := d.postForm(endpoint, data, &resp) if err != nil { return nil, err } if resp.Response.Result != "Success" { return nil, fmt.Errorf("MediaFire API error: %s", resp.Response.Result) } var newID string if srcObj.IsDir() { if len(resp.Response.NewFolderKeys) > 0 { newID = resp.Response.NewFolderKeys[0] } } else { if len(resp.Response.NewQuickKeys) > 0 { newID = resp.Response.NewQuickKeys[0] } } return &model.ObjThumb{ Object: model.Object{ ID: newID, Name: srcObj.GetName(), Size: srcObj.GetSize(), Modified: srcObj.ModTime(), Ctime: srcObj.CreateTime(), IsFolder: srcObj.IsDir(), }, Thumbnail: model.Thumbnail{}, }, nil } func (d *Mediafire) Remove(ctx context.Context, obj model.Obj) error { var data map[string]string var endpoint string if obj.IsDir() { endpoint = "/folder/delete.php" data = map[string]string{ "session_token": d.SessionToken, "response_format": "json", "folder_key": obj.GetID(), } } else { endpoint = "/file/delete.php" data = map[string]string{ "session_token": d.SessionToken, "response_format": "json", "quick_key": obj.GetID(), } } var resp MediafireRemoveResponse _, err := d.postForm(endpoint, data, &resp) if err != nil { return err } if resp.Response.Result != "Success" { return fmt.Errorf("MediaFire API error: %s", resp.Response.Result) } return nil } func (d *Mediafire) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) error { _, err := d.PutResult(ctx, dstDir, file, up) return err } func (d *Mediafire) PutResult(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) { tempFile, err := file.CacheFullInTempFile() if err != nil { return nil, err } defer tempFile.Close() osFile, ok := tempFile.(*os.File) if !ok { return nil, fmt.Errorf("expected *os.File, got %T", tempFile) } fileHash, err := d.calculateSHA256(osFile) if err != nil { return nil, err } checkResp, err := d.uploadCheck(ctx, file.GetName(), file.GetSize(), fileHash, dstDir.GetID()) if err != nil { return nil, err } if checkResp.Response.ResumableUpload.AllUnitsReady == "yes" { up(100.0) } if checkResp.Response.HashExists == "yes" && checkResp.Response.InAccount == "yes" { up(100.0) existingFile, err := d.getExistingFileInfo(ctx, fileHash, file.GetName(), dstDir.GetID()) if err == nil { return existingFile, nil } } var pollKey string if checkResp.Response.ResumableUpload.AllUnitsReady != "yes" { var err error pollKey, err = d.uploadUnits(ctx, osFile, checkResp, file.GetName(), fileHash, dstDir.GetID(), up) if err != nil { return nil, err } } else { pollKey = checkResp.Response.ResumableUpload.UploadKey } //fmt.Printf("pollKey: %+v\n", pollKey) pollResp, err := d.pollUpload(ctx, pollKey) if err != nil { return nil, err } quickKey := pollResp.Response.Doupload.QuickKey return &model.ObjThumb{ Object: model.Object{ ID: quickKey, Name: file.GetName(), Size: file.GetSize(), }, Thumbnail: model.Thumbnail{}, }, nil } func (d *Mediafire) GetArchiveMeta(ctx context.Context, obj model.Obj, args model.ArchiveArgs) (model.ArchiveMeta, error) { // TODO get archive file meta-info, return errs.NotImplement to use an internal archive tool, optional return nil, errs.NotImplement } func (d *Mediafire) ListArchive(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) ([]model.Obj, error) { // TODO list args.InnerPath in the archive obj, return errs.NotImplement to use an internal archive tool, optional return nil, errs.NotImplement } func (d *Mediafire) Extract(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) (*model.Link, error) { // TODO return link of file args.InnerPath in the archive obj, return errs.NotImplement to use an internal archive tool, optional return nil, errs.NotImplement } func (d *Mediafire) ArchiveDecompress(ctx context.Context, srcObj, dstDir model.Obj, args model.ArchiveDecompressArgs) ([]model.Obj, error) { // TODO extract args.InnerPath path in the archive srcObj to the dstDir location, optional // a folder with the same name as the archive file needs to be created to store the extracted results if args.PutIntoNewDir // return errs.NotImplement to use an internal archive tool return nil, errs.NotImplement } //func (d *Mediafire) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { // return nil, errs.NotSupport //} var _ driver.Driver = (*Mediafire)(nil)