Media is a Golang library that supports the upload of files/images/videos to a filesystem or cloud storage as well as linked videos (i.e. YouTube, Vimeo, etc.). The plugin includes:
- cropping and resizing features for images.
- optional multiple sizes for each media resource.
- Accessibility helpers.
Media accepts any and every file type, yet it associates certain file types as images or videos so as to provide helpers supporting those media's specific needs.
Images: .jpg, .jpeg, .png, .tif, .tiff, .bmp, .gif
Videos: .mp4, .m4p, .m4v, .m4v, .mov, .mpeg, .webm, .avi, .ogg, .ogv
Media depends on GORM models as it is using GORM's callbacks to handle file processing, so you will need to register callbacks first:
import (
"github.com/jinzhu/gorm"
"github.com/qor/media"
)
DB, err = gorm.Open("sqlite3", "demo_db") // [gorm](https://github.com/jinzhu/gorm)
media.RegisterCallbacks(DB)
Then add OSS(Object Storage Service) to your model:
import (
"github.com/jinzhu/gorm"
"github.com/qor/media/oss"
)
type Product struct {
gorm.Model
Image oss.OSS
}
Last, configure the storage. The default value is oss.Storage := filesystem.New("public")
. Here we configure S3 as storage.
import (
// "github.com/oss/filesystem"
"github.com/oss/s3"
)
oss.Storage := s3.New(s3.Config{AccessID: "access_id", AccessKey: "access_key", Region: "region", Bucket: "bucket", Endpoint: "cdn.getqor.com", ACL: aws.BucketCannedACLPublicRead})
// Default configuration `oss.Storage := filesystem.New("public")`
The OSS(Object Storage Service) provides a pretty simple API to operate files on filesytem or cloud storage
type StorageInterface interface {
Get(path string) (*os.File, error)
GetStream(path string) (io.ReadCloser, error)
Put(path string, reader io.Reader) (*Object, error)
Delete(path string) error
List(path string) ([]*Object, error)
GetEndpoint() string
GetURL(path string) (string, error)
}
So once you finished the setting, you could operate saved files like this:
storage := s3.New(s3.Config{AccessID: "access_id", AccessKey: "access_key", Region: "region", Bucket: "bucket", Endpoint: "cdn.getqor.com", ACL: aws.BucketCannedACLPublicRead})
// storage := filesystem.New("public")
// Save a reader interface into storage
storage.Put("/sample.txt", reader)
// Get file with path
storage.Get("/sample.txt")
// Delete file with path
storage.Delete("/sample.txt")
// List all objects under path
storage.List("/")
You can implement the GetSizes
function to predefine image sizes. The size name can be used to fetch image of corresponding size.
import (
"github.com/qor/media/oss"
"github.com/jinzhu/gorm"
)
type Product struct {
gorm.Model
Image ProductIconImageStorage
}
type ProductIconImageStorage struct{
oss.OSS
}
func (ProductIconImageStorage) GetSizes() map[string]*media.Size {
return map[string]*media.Size{
// Add padding to thumbnail if ratio doesn't match, by default, crop center
"small": {Width: 60 * 2, Height: 60 * 2, Padding: true},
"small@ld": {Width: 60, Height: 60},
"middle": {Width: 108 * 2, Height: 108 * 2},
"middle@ld": {Width: 108, Height: 108},
"big": {Width: 144 * 2, Height: 144 * 2},
"big@ld": {Width: 144, Height: 144},
}
}
// Get image's url with style
product.Image.URL("small")
product.Image.URL("big@ld")
You can also setup a media library, not use oss.OSS in model directly, then you can choose file from media library.
setup a media library
import(
"github.com/qor/admin"
"github.com/qor/media/oss"
"github.com/oss/s3"
"github.com/qor/media/media_library"
)
db.AutoMigrate(&media_library.MediaLibrary{})
adm = admin.New(&admin.AdminConfig{SiteName: "XXX", DB: db})
oss.Storage = s3.New(s3.Config{AccessID: "access_id", AccessKey: "access_key", Region: "region", Bucket: "bucket", Endpoint: "cdn.getqor.com", ACL: aws.BucketCannedACLPublicRead})
adm.AddResource(&media_library.MediaLibrary{}, &admin.Config{Name: "Media Library")
media.RegisterCallbacks(db)
use media box in model
import(
"github.com/qor/media/media_library"
"github.com/qor/media
}
type Product struct {
gorm.Model
Image media_library.MediaBox
}
res :=adm.AddResource(&Product{}, &admin.Config{Name: "Product")
res.Meta(&admin.Meta{Name: "Image", Config: &media_library.MediaBoxConfig{
Max: 1,
Sizes: map[string]*media.Size{
"m": {Width: 500,Height:500},
},
AllowType: media_library.ALLOW_TYPE_IMAGE,
}})
The default size and path for Image
. The default size is 4294967295
and default path is {repo_path}/public/system/{{class}}/{{primary_key}}/{{column}}.{{extension}}
.
You can set the path and size manually by adding tag to the field like this:
type Product struct {
gorm.Model
Image oss.OSS `sql:"size:4294967295;" media_library:"url:/backend/{{class}}/{{primary_key}}/{{column}}.{{extension}};path:./private"`
}
The media
takes two parameters, url
and path
. the url
set the relative file path and the path
set the prefix path. So suppose we uploaded a image called demo.png
. The file will be stored at {repo_path}/private/backend/products/1/demo.png
.
The http.FileServer
not only serves the files, but also shows the directory contents. This is very dangerous when you do things like
for _, path := range []string{"system", "javascripts", "stylesheets", "images"} {
mux.Handle(fmt.Sprintf("/%s/", path), http.FileServer(http.Dir("public")))
}
The files under public
will be exposed to public(especially the search engine!), Imagine someone upload a illegal or sensitive file to your server. The directory is fully visible to everyone and its indexable by search engines and boom!
To avoid this problem, we made a safer FileServer
function here. This function serves file only. So the previous code now turned into:
for _, path := range []string{"system", "javascripts", "stylesheets", "images"} {
mux.Handle(fmt.Sprintf("/%s/", path), utils.FileServer(http.Dir("public")))
}
Media Library has some features aimed at helping achieve Accessibile frontends:
- capture of a textual description for images, videos, and linked videos to aid with Accessibility.
- capture of textual transcript for videos and linked videos to aid with Accessibility.
The values captured are fed into the sub-templates for each media type to be used if/where necessary. For example, an image's HTML output (an img
tag) manifests the textual description within an alt
attribute while a video's HTML (an iframe
tag) manifests the textual description within a title
attribute.
Released under the MIT License.